You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
7.8 KiB
289 lines
7.8 KiB
/*++
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
interupt.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code to support events generated by the
|
|
sd controller.
|
|
|
|
Author:
|
|
|
|
Neil Sandlin (neilsa) 1-Jan-2002
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
VOID
|
|
SdbusEventWorkItemProc(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
SdbusReflectCardInterrupt(
|
|
IN PDEVICE_OBJECT Fdo
|
|
);
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SdbusInterrupt(
|
|
IN PKINTERRUPT InterruptObject,
|
|
PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
interrupt handler
|
|
|
|
Arguments:
|
|
|
|
InterruptObject - Pointer to the interrupt object.
|
|
Context - Pointer to the device context.
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
ULONG eventMask;
|
|
|
|
fdoExtension=((PDEVICE_OBJECT)Context)->DeviceExtension;
|
|
|
|
if (fdoExtension->Flags & SDBUS_FDO_OFFLINE) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
eventMask = (*(fdoExtension->FunctionBlock->GetPendingEvents))(fdoExtension);
|
|
|
|
if (eventMask) {
|
|
|
|
fdoExtension->IsrEventStatus |= eventMask;
|
|
|
|
(*(fdoExtension->FunctionBlock->DisableEvent))(fdoExtension, eventMask);
|
|
//
|
|
// Something changed out there.. could be
|
|
// a card insertion/removal.
|
|
// Request a DPC to check it out.
|
|
//
|
|
IoRequestDpc((PDEVICE_OBJECT) Context, NULL, NULL);
|
|
}
|
|
return (eventMask != 0);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SdbusInterruptSynchronize(
|
|
PFDO_EXTENSION fdoExtension
|
|
)
|
|
{
|
|
|
|
fdoExtension->LatchedIsrEventStatus = fdoExtension->IsrEventStatus;
|
|
fdoExtension->IsrEventStatus = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
SdbusInterruptDpc(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID SystemContext1,
|
|
IN PVOID SystemContext2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This DPC is just an intermediate step in getting to the main DPC
|
|
handler. This is used to "debounce" hardware and give it some time after
|
|
the physical interrupt has come in.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|
static ULONG IoWorkerEventTypes[] = {SDBUS_EVENT_CARD_RW_END,
|
|
SDBUS_EVENT_BUFFER_EMPTY,
|
|
SDBUS_EVENT_BUFFER_FULL,
|
|
SDBUS_EVENT_CARD_RESPONSE,
|
|
0};
|
|
UCHAR i;
|
|
ULONG acknowledgedEvents;
|
|
|
|
|
|
if (fdoExtension->Flags & SDBUS_FDO_OFFLINE) {
|
|
return;
|
|
}
|
|
|
|
|
|
KeSynchronizeExecution(fdoExtension->SdbusInterruptObject, SdbusInterruptSynchronize, fdoExtension);
|
|
|
|
DebugPrint((SDBUS_DEBUG_EVENT, "SdbusDpc: Event Status %08x\n", fdoExtension->LatchedIsrEventStatus));
|
|
|
|
if (fdoExtension->LatchedIsrEventStatus & SDBUS_EVENT_INSERTION) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_EVENT, "SdbusDpc: Card Insertion\n"));
|
|
|
|
(*(fdoExtension->FunctionBlock->AcknowledgeEvent))(fdoExtension, SDBUS_EVENT_INSERTION);
|
|
fdoExtension->LatchedIsrEventStatus &= ~SDBUS_EVENT_INSERTION;
|
|
SdbusActivateSocket(DeviceObject, NULL, NULL);
|
|
}
|
|
|
|
if (fdoExtension->LatchedIsrEventStatus & SDBUS_EVENT_REMOVAL) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_EVENT, "SdbusDpc: Card Removal\n"));
|
|
|
|
(*(fdoExtension->FunctionBlock->AcknowledgeEvent))(fdoExtension, SDBUS_EVENT_REMOVAL);
|
|
fdoExtension->LatchedIsrEventStatus &= ~SDBUS_EVENT_REMOVAL;
|
|
SdbusActivateSocket(DeviceObject, NULL, NULL);
|
|
|
|
}
|
|
|
|
acknowledgedEvents = 0;
|
|
|
|
for(i = 0; IoWorkerEventTypes[i] != 0; i++) {
|
|
if (fdoExtension->LatchedIsrEventStatus & IoWorkerEventTypes[i]) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_EVENT, "SdbusDpc: received event %08x - %s\n",
|
|
IoWorkerEventTypes[i], EVENT_STRING(IoWorkerEventTypes[i])));
|
|
|
|
(*(fdoExtension->FunctionBlock->AcknowledgeEvent))(fdoExtension, IoWorkerEventTypes[i]);
|
|
|
|
DebugPrint((SDBUS_DEBUG_EVENT, "SdbusDpc: ack'd event %08x - %s\n",
|
|
IoWorkerEventTypes[i], EVENT_STRING(IoWorkerEventTypes[i])));
|
|
|
|
acknowledgedEvents |= IoWorkerEventTypes[i];
|
|
fdoExtension->LatchedIsrEventStatus &= ~IoWorkerEventTypes[i];
|
|
}
|
|
}
|
|
|
|
|
|
if (acknowledgedEvents) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_EVENT, "SdbusDpc: dispatching event %08x\n", acknowledgedEvents));
|
|
SdbusPushWorkerEvent(fdoExtension, acknowledgedEvents);
|
|
}
|
|
|
|
//
|
|
// Now check to see if the card has interrupted, and call back to the function driver
|
|
//
|
|
if (fdoExtension->LatchedIsrEventStatus & SDBUS_EVENT_CARD_INTERRUPT) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_EVENT, "SdbusDpc: got CARD INTERRUPT\n"));
|
|
|
|
SdbusReflectCardInterrupt(DeviceObject);
|
|
|
|
fdoExtension->LatchedIsrEventStatus &= ~SDBUS_EVENT_CARD_INTERRUPT;
|
|
}
|
|
|
|
ASSERT(fdoExtension->LatchedIsrEventStatus == 0);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SdbusReflectCardInterrupt(
|
|
IN PDEVICE_OBJECT Fdo
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PDEVICE_OBJECT pdo;
|
|
PPDO_EXTENSION pdoExtension;
|
|
|
|
//
|
|
// ISSUE: NEED TO IMPLEMENT:
|
|
// need to queue an IoWorker packet to read the CCCR and find out which
|
|
// function is interrupting. For now, assume there is only a single I/O function,
|
|
// and use the first callback found.
|
|
//
|
|
for (pdo = fdoExtension->PdoList; pdo != NULL; pdo = pdoExtension->NextPdoInFdoChain) {
|
|
pdoExtension = pdo->DeviceExtension;
|
|
|
|
if (pdoExtension->Flags & SDBUS_PDO_GENERATES_IRQ) {
|
|
|
|
|
|
if (pdoExtension->Flags & SDBUS_PDO_DPC_CALLBACK) {
|
|
|
|
pdoExtension->Flags |= SDBUS_PDO_CALLBACK_IN_SERVICE;
|
|
(pdoExtension->CallbackRoutine)(pdoExtension->CallbackRoutineContext, 0);
|
|
|
|
} else {
|
|
pdoExtension->Flags |= SDBUS_PDO_CALLBACK_REQUESTED;
|
|
KeSetEvent(&fdoExtension->CardInterruptEvent, 0, FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SdbusEventWorkItemProc(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PKEVENT Events[2] = {&fdoExtension->CardInterruptEvent, &fdoExtension->WorkItemExitEvent};
|
|
PDEVICE_OBJECT pdo;
|
|
PPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
|
|
while(TRUE){
|
|
|
|
status = KeWaitForMultipleObjects(2, Events, WaitAny,
|
|
Executive, KernelMode, FALSE,
|
|
NULL, NULL);
|
|
|
|
if ((fdoExtension->Flags & SDBUS_FDO_WORK_ITEM_ACTIVE) == 0) {
|
|
break;
|
|
}
|
|
|
|
for (pdo = fdoExtension->PdoList; pdo != NULL; pdo = pdoExtension->NextPdoInFdoChain) {
|
|
pdoExtension = pdo->DeviceExtension;
|
|
|
|
if (pdoExtension->Flags & SDBUS_PDO_GENERATES_IRQ) {
|
|
|
|
DebugPrint((SDBUS_DEBUG_CARD_EVT, "WorkItemProc: CallBack %08x %08x\n", pdoExtension->CallbackRoutine,
|
|
pdoExtension->CallbackRoutineContext));
|
|
|
|
ASSERT((pdoExtension->Flags & SDBUS_PDO_CALLBACK_IN_SERVICE) == 0);
|
|
|
|
pdoExtension->Flags |= SDBUS_PDO_CALLBACK_IN_SERVICE;
|
|
pdoExtension->Flags &= ~SDBUS_PDO_CALLBACK_REQUESTED;
|
|
(pdoExtension->CallbackRoutine)(pdoExtension->CallbackRoutineContext, 0);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|