📄 callback.c
字号:
PCALLBACK_STRUCT
CallbackType(
CARD_EVENT MajorEvent,
CARD_EVENT SubEvent,
PCLIENT_DRIVER pReqClient,
CARD_SOCKET_HANDLE hSock,
UINT fFlags,
UINT DriverType
)
{
PCLIENT_DRIVER pClient;
PCALLBACK_STRUCT pLast;
PCALLBACK_STRUCT pEvent;
UINT8 StartFunction, EndFunction;
pLast = NULL;
//
// Check if a notification is needed for all functions
//
if (fFlags & CALLBACK_FLAG_ALL_FUNCTIONS) {
StartFunction = 0;
EndFunction = v_Sockets[hSock.uSocket].cFunctions;
//
// If the user had previously disabled the PC card, we still want a
// CE_CARD_REMOVAL message after standby. This check covers that case.
//
if (EndFunction == 0) {
EndFunction = 1;
}
} else {
StartFunction = hSock.uFunction;
EndFunction = hSock.uFunction + 1;
}
//
// Callback all clients of the specified type.
//
EnterCriticalSection(&v_ClientCrit);
pClient = (PCLIENT_DRIVER)v_ClientList.Flink;
while (pClient != (PCLIENT_DRIVER)&v_ClientList) {
if (pClient->Parms.fAttributes & DriverType) {
for (hSock.uFunction = StartFunction;
hSock.uFunction < EndFunction;
hSock.uFunction++) {
if (ShouldCallback(pClient, MajorEvent, SubEvent, hSock)) {
pEvent = alloc(sizeof(CALLBACK_STRUCT));
if (pEvent) {
pEvent->MajorEvent = MajorEvent;
pEvent->SubEvent = SubEvent;
pEvent->pReqClient = (pReqClient == NULL) ? NULL : pReqClient->hClient;
pEvent->pDestClient = (pClient == NULL) ? NULL : pClient->hClient;
pEvent->hSock = hSock;
pEvent->fFlags = fFlags;
EnqueueEvent(pEvent);
pLast = pEvent;
}
}
}
}
pClient = (PCLIENT_DRIVER)pClient->List.Flink;
}
LeaveCriticalSection(&v_ClientCrit);
return pLast;
} // CallbackType
//
// Broadcast a card event message to all registered clients in the order
// specified by the PCMCIA standard.
//
STATUS
CallbackAll(
CARD_EVENT MajorEvent,
CARD_EVENT SubEvent,
PCLIENT_DRIVER pReqClient,
CARD_SOCKET_HANDLE hSock,
UINT fFlags
)
{
UINT fDriverType;
PCALLBACK_STRUCT pLast;
PCALLBACK_STRUCT pCurr;
pLast = NULL;
//
// The following for loop relies on the fact that CLIENT_ATTR_IO_DRIVER,
// CLIENT_ATTR_MTD_DRIVER and CLIENT_ATTR_MEM_DRIVER are one right shift
// different from each other. This conveniently results in the PCMCIA
// specified client type order for callbacks.
//
// NOTE: I/O driver clients were linked in reverse order by
// CardRegisterClient
//
EnterCriticalSection(&v_CallbackCrit);
for (fDriverType = CLIENT_ATTR_IO_DRIVER; fDriverType; fDriverType >>= 1) {
if (pCurr = CallbackType(
MajorEvent,
SubEvent,
pReqClient,
hSock,
fFlags,
fDriverType)) {
pLast = pCurr;
}
}
if (pLast) {
pLast->fFlags |= CALLBACK_FLAG_LAST;
}
LeaveCriticalSection(&v_CallbackCrit);
if (pLast) {
StartCallbacks();
}
return CERR_SUCCESS;
} // CallbackAll
//
// Perform an insertion callback to a newly registered client
// for all sockets in the system.
//
STATUS
CallbackSockets(
PCLIENT_DRIVER pClient
)
{
PLOG_SOCKET pLsock;
PCALLBACK_STRUCT pEvent;
PCALLBACK_STRUCT pLast;
CARD_SOCKET_HANDLE hSock;
int i;
if (pClient->CallBackFn == NULL) {
return CERR_SUCCESS;
}
pLast = NULL;
//
// If both of these options are clear, then don't send any callbacks.
//
if ((pClient->Parms.fAttributes &
(CLIENT_ATTR_NOTIFY_SHARED|CLIENT_ATTR_NOTIFY_EXCLUSIVE)) == 0) {
goto cbs_complete;
}
EnterCriticalSection(&v_CallbackCrit);
//
// See if this client wants any callbacks. If so, then he gets a
// CE_CARD_INSERTION for every socket/function available and then a
// CE_REGISTRATION_COMPLETE.
//
EnterCriticalSection(&v_SocketCrit);
for (i = 0; i < v_cSockets; i++) {
if (IsCardInserted(i)) {
for (pLsock = v_Sockets[i].pLsock; pLsock; pLsock = pLsock->Next) {
pEvent = alloc(sizeof(CALLBACK_STRUCT));
if (pEvent) {
pEvent->MajorEvent = CE_REGISTRATION_COMPLETE;
pEvent->SubEvent = CE_CARD_INSERTION;
pEvent->pDestClient = (pClient == NULL) ? NULL : pClient->hClient;
pEvent->pReqClient = (pClient == NULL) ? NULL : pClient->hClient;
pEvent->hSock = pLsock->hSock;
pEvent->fFlags = 0;
EnqueueEvent(pEvent);
pLast = pEvent;
}
}
}
}
LeaveCriticalSection(&v_SocketCrit);
if (pLast) {
pLast->fFlags |= CALLBACK_FLAG_LAST;
}
LeaveCriticalSection(&v_CallbackCrit);
if (pLast) {
StartCallbacks();
}
cbs_complete:
if (pLast == NULL) {
hSock.uSocket = 0;
hSock.uFunction = 0;
//
// If no insertion callbacks were made, then send CE_REGISTRATION_COMPLETE
// otherwise CallbackThread will send a CE_REGISTRATION_COMPLETE after
// the last CE_CARD_INSERTION message.
//
CallbackOne(
CE_REGISTRATION_COMPLETE,
CE_REGISTRATION_COMPLETE,
pClient,
hSock);
}
return CERR_SUCCESS;
} // CallbackSockets
//
// Call client driver's status callback function in a protected manner.
//
// Returns the return code from the client driver.
// If an exception is taken, then CERR_SUCCESS is returned.
//
STATUS
CallClient(
CLIENT_CALLBACK CallBackFn,
CARD_EVENT Event,
CARD_SOCKET_HANDLE hSock,
PCARD_EVENT_PARMS pParms,
PCLIENT_DRIVER pClient
)
{
STATUS status;
DEBUGMSG(ZONE_CALLBACK, (TEXT("PCMCIA:CallClient entered\r\n")));
status = CERR_SUCCESS;
try {
if (CallBackFn != NULL) {
status = (CallBackFn)(Event, hSock, pParms);
} else {
DEBUGMSG(ZONE_CALLBACK, (TEXT("PCMCIA:CallClient - CallBackFn == NULL\r\n")));
}
} except (GetExceptionCode() == STATUS_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
DEBUGMSG(ZONE_CALLBACK|ZONE_WARNING,
(TEXT("PCMCIA:CallClient: Client's callback hit an exception!\r\n")));
if (IsValidClient(pClient))
CardDeregisterClient(pClient->hClient);
}
DEBUGMSG(ZONE_CALLBACK, (TEXT("PCMCIA:CallClient done\r\n")));
return status;
} // CallClient
//
// Function to figure out whether to send a CE_PM_RESUME and send it when
// appropriate
//
void
CallbackPmResume(void)
{
BOOL bPmResume;
UINT uSocket;
CARD_SOCKET_HANDLE hSock;
bPmResume = TRUE;
for (uSocket = 0; uSocket < (UINT8)v_cSockets; uSocket++) {
if ((v_Sockets[uSocket].PowerState != POWER_ON) ||
(v_Sockets[uSocket].fFlags & PHYS_SOCK_FLAG_RESUMING)) {
bPmResume = FALSE;
break;
}
}
if (bPmResume) {
//
// At this point all the insertion notices have been queued for any
// cards that were in the device after a resume. Now indicate a
// CE_PM_RESUME which device.exe will use as a signal to notify the
// filesystem that it's safe to do pc card I/O.
//
DEBUGMSG(ZONE_POWER, (TEXT("PCMCIA:CallbackPmResume sending CE_PM_RESUME\r\n")));
hSock.uSocket = 0;
hSock.uFunction = 0;
CallbackAll(
CE_PM_RESUME,
CE_PM_RESUME,
NULL,
hSock,
0);
}
} // CallbackPmResume
//
// CheckForUnload - look for a CE_CARDSERV_UNLOAD on socket
//
BOOL
CheckForUnload(
UINT8 uSocket
)
{
BOOL bRet = FALSE;
PCALLBACK_STRUCT pEvent, pPrev;
EnterCriticalSection(&v_CallbackCrit);
pPrev = NULL;
for (pEvent = v_CallbackHead; pEvent != NULL; pEvent = pEvent->Next) {
if (pEvent->MajorEvent == CE_CARDSERV_UNLOAD &&
pEvent->hSock.uSocket == uSocket) {
DEBUGMSG(ZONE_CALLBACK, (TEXT("CE_CARDSERV_LOAD/CE_CARDSERV_UNLOAD found on socket %d\r\n"), uSocket));
// Dequeue and discard the CE_CARDSERV_UNLOAD
if (pPrev != NULL) {
pPrev->Next = pEvent->Next;
} else {
v_CallbackHead = pEvent->Next;
}
if (v_CallbackTail == pEvent) {
v_CallbackTail = pPrev;
}
free(pEvent);
// Signal that unload was found, so that CE_CARDSERV_LOAD can be aborted
bRet = TRUE;
break;
}
pPrev = pEvent;
}
LeaveCriticalSection(&v_CallbackCrit);
return bRet;
}
//
// Callback Thread - pull CALLBACK_STRUCTs off the callback queue and callback
// the specified client. Perform any special processing for multi-stage
// callback sequences.
//
UINT
CallbackThread(
UINT Nothing
)
{
STATUS status;
CARD_EVENT_PARMS Parms;
PCALLBACK_STRUCT pEvent;
BOOL fCallAll, bUnloadDriver;
CARD_EVENT NextEvent;
PDCARD_SOCKET_STATE State;
PCLIENT_DRIVER pClient;
PLOG_SOCKET pLsock;
UINT i;
#ifdef DEBUG
LPTSTR MajorName;
LPTSTR SubName;
#endif
DEBUGMSG(ZONE_CALLBACK,
(TEXT("PCMCIA:CallbackThread: entered %d\r\n"), ++g_Reentry));
while ((pEvent = DequeueEvent()) != NULL) {
// Handle special operations (these don't involve real callbacks
// but they need to be serialized on the callback thread).
switch (pEvent->MajorEvent) {
case CE_CARDSERV_LOAD:
if (!(v_Sockets[pEvent->hSock.uSocket].fFlags & PHYS_SOCK_FLAG_RESETTING)) {
if (!CheckForUnload(pEvent->hSock.uSocket)) {
// allow PCMCIA CD signals to settle (and user time to fully insert card)
Sleep(750);
if (!CheckForUnload(pEvent->hSock.uSocket)) {
CardServLoadDriver(pEvent->hSock.uSocket);
}
}
} else {
// Since CardServLoadDriver will not be doing insertion callbacks, do them here.
CallbackAll(CE_CARD_INSERTION, CE_CARD_INSERTION, NULL, pEvent->hSock, CALLBACK_FLAG_ALL_FUNCTIONS);
}
v_Sockets[pEvent->hSock.uSocket].fFlags &= ~PHYS_SOCK_FLAG_RESETTING;
goto cbt_next1;
case CE_CARDSERV_UNLOAD:
bUnloadDriver = ((v_Sockets[pEvent->hSock.uSocket].pLsock == NULL) ||
!(v_Sockets[pEvent->hSock.uSocket].fFlags & PHYS_SOCK_FLAG_RESUMING));
// Check if all functions do not want to be unloaded
if (!bUnloadDriver) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -