📄 callback.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
callback.c
Abstract:
This file implements the PCMCIA model device driver client callback
functions. This is provided as a sample to platform writers and is
expected to be able to be used without modification on most (if not
all) hardware platforms.
Functions:
FindEventName()
EnqueueEvent()
DequeueEvent()
ShouldCallback()
CallbackOne()
CallbackType()
CallbackAll()
CallbackSockets()
CallClient()
CallbackThread()
Notes:
--*/
#include <windows.h>
#include <types.h>
#include <excpt.h>
#include <cardserv.h>
#include <sockserv.h>
#include <linklist.h>
#include <pcmcia.h>
#include <extern.h>
UINT CallbackThread(UINT Nothing);
#ifdef DEBUG
//
// Debug data and function for callback thread
//
#define LAST_EVENT_CODE ((CARD_EVENT) -1)
typedef struct _EVENT_NAME_TBL {
CARD_EVENT EventCode;
LPTSTR pEventName;
} EVENT_NAME_TBL, *PEVENT_NAME_TBL;
//
// Table of callback event codes and their names.
// NOTE: The names with ! at the end are not expected.
//
EVENT_NAME_TBL v_EventNames[] = {
{ CE_BATTERY_DEAD, TEXT("CE_BATTERY_DEAD") },
{ CE_BATTERY_LOW, TEXT("CE_BATTERY_LOW") },
{ CE_CARD_LOCK, TEXT("CE_CARD_LOCK") },
{ CE_CARD_READY, TEXT("CE_CARD_READY") },
{ CE_CARD_REMOVAL, TEXT("CE_CARD_REMOVAL") },
{ CE_CARD_UNLOCK, TEXT("CE_CARD_UNLOCK") },
{ CE_EJECTION_COMPLETE, TEXT("CE_EJECTION_COMPLETE!") },
{ CE_EJECTION_REQUEST, TEXT("CE_EJECTION_REQUEST!") },
{ CE_INSERTION_COMPLETE, TEXT("CE_INSERTION_COMPLETE!") },
{ CE_INSERTION_REQUEST, TEXT("CE_INSERTION_REQUEST!") },
{ CE_PM_RESUME, TEXT("CE_PM_RESUME") },
{ CE_PM_SUSPEND, TEXT("CE_PM_SUSPEND!") },
{ CE_EXCLUSIVE_COMPLETE, TEXT("CE_EXCLUSIVE_COMPLETE") },
{ CE_EXCLUSIVE_REQUEST, TEXT("CE_EXCLUSIVE_REQUEST") },
{ CE_RESET_PHYSICAL, TEXT("CE_RESET_PHYSICAL") },
{ CE_RESET_REQUEST, TEXT("CE_RESET_REQUEST") },
{ CE_CARD_RESET, TEXT("CE_CARD_RESET") },
{ CE_MTD_REQUEST, TEXT("CE_MTD_REQUEST!") },
{ CE_CLIENT_INFO, TEXT("CE_CLIENT_INFO!") },
{ CE_TIMER_EXPIRED, TEXT("CE_TIMER_EXPIRED!") },
{ CE_SS_UPDATED, TEXT("CE_SS_UPDATED!") },
{ CE_WRITE_PROTECT, TEXT("CE_WRITE_PROTECT") },
{ CE_CARD_INSERTION, TEXT("CE_CARD_INSERTION") },
{ CE_RESET_COMPLETE, TEXT("CE_RESET_COMPLETE") },
{ CE_ERASE_COMPLETE, TEXT("CE_ERASE_COMPLETE!") },
{ CE_REGISTRATION_COMPLETE, TEXT("CE_REGISTRATION_COMPLETE") },
{ CE_STATUS_CHANGE_INTERRUPT, TEXT("CE_STATUS_CHANGE_INTERRUPT") },
{ CE_CARDSERV_LOAD, TEXT("CE_CARDSERV_LOAD") },
{ CE_CARDSERV_UNLOAD, TEXT("CE_CARDSERV_UNLOAD") },
{ LAST_EVENT_CODE, TEXT("Unknown Event!") },
};
LPTSTR
FindEventName(
CARD_EVENT EventCode
)
{
PEVENT_NAME_TBL pEvent = v_EventNames;
while (pEvent->EventCode != LAST_EVENT_CODE) {
if (pEvent->EventCode == EventCode) {
return pEvent->pEventName;
}
pEvent++;
}
return pEvent->pEventName;
}
DWORD g_Reentry; // used to debug CallbackThread
#endif // DEBUG
//
// StartCallbacks - function to invoke the CallbackThread
//
VOID StartCallbacks(VOID)
{
DEBUGCHK(v_CallbackEvent != NULL);
SetEvent(v_CallbackEvent);
}
//
// Put a CALLBACK_STRUCT at the end of the callback queue.
//
VOID
EnqueueEvent(
PCALLBACK_STRUCT pEvent
)
{
EnterCriticalSection(&v_CallbackCrit);
pEvent->Next = NULL;
//
// Link the event structure at the tail of the list
//
if (v_CallbackTail == NULL) { // empty list?
v_CallbackHead = pEvent;
v_CallbackTail = pEvent;
} else {
v_CallbackTail->Next = pEvent;
v_CallbackTail = pEvent;
}
DEBUGMSG(ZONE_CALLBACK,
(TEXT("PCMCIA:Enqueued %s for client 0x%x, socket %d, function %d\r\n"),
FindEventName(pEvent->MajorEvent), pEvent->pDestClient,
pEvent->hSock.uSocket, pEvent->hSock.uFunction));
EnterCriticalSection(&v_BatteryCrit);
if (v_hBatteryThread[pEvent->hSock.uSocket] != 0) {
if (v_hGwesEvent == NULL ||
WaitForSingleObject(v_hGwesEvent, INFINITE) != WAIT_OBJECT_0 ||
(NULL == v_pfnPostThreadMessageW) || !v_pfnPostThreadMessageW(
v_hBatteryThread[pEvent->hSock.uSocket],
WM_QUIT, 0, 0)) {
DEBUGMSG(ZONE_WARNING|ZONE_CALLBACK|ZONE_INIT,
(TEXT("PCMCIA:EnqueueEvent:PostThreadMessage Failed (%d)\r\n"),
GetLastError()));
}
v_fBattery[pEvent->hSock.uSocket] = FALSE;
v_hBatteryThread[pEvent->hSock.uSocket] = 0;
}
LeaveCriticalSection(&v_BatteryCrit);
LeaveCriticalSection(&v_CallbackCrit);
} // EnqueueEvent
//
// Remove the first CALLBACK_STRUCT from the callback queue
//
PCALLBACK_STRUCT
DequeueEvent(VOID)
{
PCALLBACK_STRUCT pEvent;
DWORD dwStatus;
// wait for an event to arrive
do {
EnterCriticalSection(&v_CallbackCrit);
pEvent = v_CallbackHead;
LeaveCriticalSection(&v_CallbackCrit);
if(pEvent == NULL) {
dwStatus = WaitForSingleObject(v_CallbackEvent, INFINITE);
DEBUGCHK(dwStatus == WAIT_OBJECT_0);
dwStatus = dwStatus; // avoid compiler warning about unused variable
}
} while(pEvent == NULL);
EnterCriticalSection(&v_CallbackCrit);
pEvent = v_CallbackHead;
if (pEvent) {
v_CallbackHead = pEvent->Next;
if (v_CallbackHead == NULL) {
v_CallbackTail = NULL;
}
DEBUGMSG(ZONE_CALLBACK,
(TEXT("PCMCIA:Dequeued %s for client 0x%x, socket %d, function %d\r\n"),
FindEventName(pEvent->MajorEvent), pEvent->pDestClient,
pEvent->hSock.uSocket, pEvent->hSock.uFunction));
}
#ifdef DEBUG
if (v_CallbackHead == NULL) {
if (v_CallbackTail != NULL) {
DEBUGMSG(1|ZONE_ERROR|ZONE_CALLBACK,
(TEXT("PCMCIA:v_CallbackHead=0 but v_CallbackTail = 0x%x\r\n"),
v_CallbackTail));
}
}
if (v_CallbackTail == NULL) {
if (v_CallbackHead != NULL) {
DEBUGMSG(1|ZONE_ERROR|ZONE_CALLBACK,
(TEXT("PCMCIA:v_CallbackTail=0 but v_CallbackHead = 0x%x\r\n"),
v_CallbackHead));
}
}
#endif
LeaveCriticalSection(&v_CallbackCrit);
return pEvent;
} // DequeueEvent
//
// Check if the specified client wants this type of event.
//
// Return: TRUE => client wants this callback
// FALSE => don't callback client for this event
BOOL
ShouldCallback(
PCLIENT_DRIVER pClient,
CARD_EVENT MajorEvent,
CARD_EVENT EventCode,
CARD_SOCKET_HANDLE hSock
)
{
UINT EventMask;
PEVENT_ATTR pAttr;
PCLIENT_SOCKET pCsock;
PCALLBACK_STRUCT pEvent;
if (pClient == NULL) {
// This is an internal operation and does not generate a true callback.
return TRUE;
}
if (pClient->CallBackFn == NULL) {
return FALSE;
}
pAttr = (PEVENT_ATTR)v_EventMap;
EventMask = (UINT) -1; // Default is that he gets it.
//
// Find the EventMask associated with this EventCode
//
while (pAttr->EventCode != (UINT16)-1) {
if (pAttr->EventCode == EventCode) {
EventMask = pAttr->EventMask;
break;
}
pAttr++;
}
//
// Check the socket specific eventmask
//
if ((pCsock = I_FindClientSocket(hSock, pClient)) != NULL) {
//
// Check the socket event mask - if we're dealing with a CE_PM_RESUME
// (global event) try the global event mask as well
//
if (!(pCsock->fEventMask & EventMask) && EventCode != CE_PM_RESUME) {
DEBUGMSG(ZONE_CALLBACK,
(TEXT("PCMCIA:ShouldCallback - Client 0x%x doesn't want a %s event\r\n"),
pClient->hClient, FindEventName(EventCode)));
return FALSE;
}
}
//
// Check the global event mask
//
if (!(pClient->Parms.fEventMask & EventMask)) {
DEBUGMSG(ZONE_CALLBACK,
(TEXT("PCMCIA:ShouldCallback - Client 0x%x doesn't want a %s event\r\n"),
pClient->hClient, FindEventName(EventCode)));
return FALSE;
}
//
// There should be at most only one CE_PM_RESUME per client.
//
EnterCriticalSection(&v_CallbackCrit);
pEvent = v_CallbackHead;
while (pEvent) {
if ((EventCode == CE_PM_RESUME) &&
(pEvent->MajorEvent == CE_PM_RESUME) &&
(pEvent->pDestClient == pClient->hClient)) {
LeaveCriticalSection(&v_CallbackCrit);
DEBUGMSG(ZONE_CALLBACK,
(TEXT("PCMCIA:ShouldCallback - Client already getting CE_PM_RESUME\r\n")));
return FALSE;
} else if ((pEvent->MajorEvent == MajorEvent) &&
(pEvent->SubEvent == EventCode) &&
(pEvent->hSock.uSocket == hSock.uSocket) &&
(pEvent->hSock.uFunction == hSock.uFunction) &&
(pEvent->pReqClient == ((pClient == NULL) ? NULL : pClient->hClient)) &&
(pEvent->pDestClient == ((pClient == NULL) ? NULL : pClient->hClient))) {
LeaveCriticalSection(&v_CallbackCrit);
DEBUGMSG(ZONE_CALLBACK,
(TEXT("PCMCIA:ShouldCallback - Stopped duplicate %s\r\n"),
FindEventName(EventCode)));
return FALSE;
}
pEvent = pEvent->Next;
}
LeaveCriticalSection(&v_CallbackCrit);
return TRUE;
} // ShouldCallback
//
// Allocate and queue a CALLBACK_STRUCT for the specified client.
//
PCALLBACK_STRUCT
CallbackOne(
CARD_EVENT MajorEvent,
CARD_EVENT SubEvent,
PCLIENT_DRIVER pReqClient,
CARD_SOCKET_HANDLE hSock
)
{
PCALLBACK_STRUCT pEvent;
if (!ShouldCallback(pReqClient, MajorEvent, SubEvent, hSock)) {
return NULL;
}
pEvent = alloc(sizeof(CALLBACK_STRUCT));
if (pEvent) {
pEvent->MajorEvent = MajorEvent;
pEvent->SubEvent = SubEvent;
pEvent->pDestClient = (pReqClient == NULL) ? NULL : pReqClient->hClient;
pEvent->pReqClient = (pReqClient == NULL) ? NULL : pReqClient->hClient;
pEvent->hSock = hSock;
pEvent->fFlags = CALLBACK_FLAG_LAST;
EnqueueEvent(pEvent);
StartCallbacks();
return pEvent;
}
return NULL;
} // CallbackOne
//
// Callback all clients of the specified type.
//
// NOTE: The caller of this function must own v_CallbackCrit
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -