410 lines
7.7 KiB
C
410 lines
7.7 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
pcmcia.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the code that controls the PCMCIA slots.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bob Rinne (BobRi) 3-Aug-1994
|
|||
|
Jeff McLeman 12-Apr-1994
|
|||
|
Ravisankar Pudipeddi (ravisp) 1-Nov-96
|
|||
|
Neil Sandlin (neilsa) 1-Jun-1999
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History :
|
|||
|
6-Apr-95
|
|||
|
Modified for databook support - John Keys Databook
|
|||
|
1-Nov-96
|
|||
|
Total overhaul to make this a bus enumerator - Ravisankar Pudipeddi (ravisp)
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
|
|||
|
//
|
|||
|
// Internal References
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
PcmciaUnload(
|
|||
|
IN PDRIVER_OBJECT DriverObject
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT,DriverEntry)
|
|||
|
#pragma alloc_text(PAGE, PcmciaUnload)
|
|||
|
#pragma alloc_text(PAGE, PcmciaOpenCloseDispatch)
|
|||
|
#pragma alloc_text(PAGE, PcmciaCleanupDispatch)
|
|||
|
#pragma alloc_text(PAGE, PcmciaFdoSystemControl)
|
|||
|
#pragma alloc_text(PAGE, PcmciaPdoSystemControl)
|
|||
|
#endif
|
|||
|
|
|||
|
PUNICODE_STRING DriverRegistryPath;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DriverEntry(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PUNICODE_STRING RegistryPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The entry point that the system point calls to initialize
|
|||
|
any driver.
|
|||
|
Since this is a plug'n'play driver, we should return after setting
|
|||
|
the entry points & initializing our dispatch table.
|
|||
|
Currently we also detect our own PCMCIA controllers and report
|
|||
|
them - which should not be needed in the future when a root bus
|
|||
|
driver such as PCI or ISAPNP will locate the controllers for us.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Pointer to object representing this driver
|
|||
|
|
|||
|
RegistryPath - Pointer the the registry key for this driver
|
|||
|
under \CurrentControlSet\Services
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DEBUG_INFO,"Initializing Driver\n"));
|
|||
|
|
|||
|
//
|
|||
|
// Load in common parameters from the registry
|
|||
|
//
|
|||
|
status = PcmciaLoadGlobalRegistryValues();
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// Set up the device driver entry points.
|
|||
|
//
|
|||
|
|
|||
|
DriverObject->DriverExtension->AddDevice = PcmciaAddDevice;
|
|||
|
|
|||
|
DriverObject->DriverUnload = PcmciaUnload;
|
|||
|
//
|
|||
|
//
|
|||
|
// Save our registry path
|
|||
|
DriverRegistryPath = RegistryPath;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the event used by the delay execution
|
|||
|
// routine.
|
|||
|
//
|
|||
|
KeInitializeEvent (&PcmciaDelayTimerEvent,
|
|||
|
NotificationEvent,
|
|||
|
FALSE);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize tone generation objects
|
|||
|
//
|
|||
|
KeInitializeTimer(&PcmciaToneTimer);
|
|||
|
KeInitializeDpc(&PcmciaToneDpc, PcmciaPlayToneCompletion, NULL);
|
|||
|
KeInitializeSpinLock(&PcmciaToneLock);
|
|||
|
//
|
|||
|
// Initialize global lock
|
|||
|
//
|
|||
|
KeInitializeSpinLock(&PcmciaGlobalLock);
|
|||
|
|
|||
|
//
|
|||
|
// Init device dispatch table
|
|||
|
//
|
|||
|
PcmciaInitDeviceDispatchTable(DriverObject);
|
|||
|
|
|||
|
//
|
|||
|
// Locate PCMCIA controllers and report them - this
|
|||
|
// is temporary - till the detection for these
|
|||
|
// controllers is moved into
|
|||
|
// appropriate root bus driver such as the PCI bus driver..
|
|||
|
|
|||
|
// if (PcmciaLegacyDetectionOk()) {
|
|||
|
status = PcmciaDetectPcmciaControllers(DriverObject,RegistryPath);
|
|||
|
// }
|
|||
|
|
|||
|
//
|
|||
|
// Ignore the status. Regardless of whether we found controllers or not
|
|||
|
// we need to stick around since we might get an AddDevice non-legacy
|
|||
|
// controllers
|
|||
|
//
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaOpenCloseDispatch(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Open or Close device routine
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer to the device object.
|
|||
|
Irp - Pointer to the IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DEBUG_INFO, "PCMCIA: Open / close of Pcmcia controller for IO \n"));
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
IoCompleteRequest(Irp, 0);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaCleanupDispatch(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Handles IRP_MJ_CLEANUP
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer to the device object.
|
|||
|
Irp - Pointer to the IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DEBUG_INFO, "PCMCIA: Cleanup of Pcmcia controller for IO \n"));
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
IoCompleteRequest(Irp, 0);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaFdoSystemControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Handles IRP_MJ_SYSTEM_CONTROL
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer to the device object.
|
|||
|
Irp - Pointer to the IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
return IoCallDriver(fdoExtension->LowerDevice, Irp);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcmciaPdoSystemControl(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Handles IRP_MJ_SYSTEM_CONTROL
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer to the device object.
|
|||
|
Irp - Pointer to the IRP
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PPDO_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (IsCardBusCard(pdoExtension)) {
|
|||
|
//
|
|||
|
// Pass irp down the stack for cardbus cards
|
|||
|
//
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
status = IoCallDriver(pdoExtension->LowerDevice, Irp);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Complete the irp for R2 cards
|
|||
|
//
|
|||
|
status = Irp->IoStatus.Status;
|
|||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PcmciaUnload(
|
|||
|
IN PDRIVER_OBJECT DriverObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Unloads the driver after cleaning up
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject -- THe device drivers object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_OBJECT fdo, pdo, nextFdo, nextPdo;
|
|||
|
PFDO_EXTENSION fdoExtension;
|
|||
|
PSOCKET socket, nextSocket;
|
|||
|
PPCMCIA_NTDETECT_DATA pData, pNextData;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaUnload Entered\n"));
|
|||
|
|
|||
|
pData = pNtDetectDataList;
|
|||
|
while(pData != NULL) {
|
|||
|
pNextData = pData->Next;
|
|||
|
ExFreePool(pData);
|
|||
|
pData = pNextData;
|
|||
|
}
|
|||
|
|
|||
|
for (fdo = FdoList; fdo !=NULL ; fdo = nextFdo) {
|
|||
|
|
|||
|
fdoExtension = fdo->DeviceExtension;
|
|||
|
MarkDeviceDeleted(fdoExtension);
|
|||
|
|
|||
|
if (fdoExtension->PcmciaInterruptObject) {
|
|||
|
IoDisconnectInterrupt(fdoExtension->PcmciaInterruptObject);
|
|||
|
}
|
|||
|
//
|
|||
|
// Cleanup socket structures
|
|||
|
//
|
|||
|
for (socket=fdoExtension->SocketList; socket !=NULL; socket=nextSocket) {
|
|||
|
nextSocket = socket->NextSocket;
|
|||
|
ExFreePool(socket);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove symbolic links
|
|||
|
//
|
|||
|
if (fdoExtension->LinkName.Buffer != NULL) {
|
|||
|
IoDeleteSymbolicLink(&fdoExtension->LinkName);
|
|||
|
RtlFreeUnicodeString(&fdoExtension->LinkName);
|
|||
|
}
|
|||
|
//
|
|||
|
// Clean up all the PDOs
|
|||
|
//
|
|||
|
for (pdo=fdoExtension->PdoList; pdo != NULL; pdo=nextPdo) {
|
|||
|
nextPdo = ((PPDO_EXTENSION) pdo->DeviceExtension)->NextPdoInFdoChain;
|
|||
|
MarkDeviceDeleted((PPDO_EXTENSION)pdo->DeviceExtension);
|
|||
|
PcmciaCleanupPdo(pdo);
|
|||
|
IoDeleteDevice(pdo);
|
|||
|
}
|
|||
|
|
|||
|
if (fdoExtension->Flags & PCMCIA_USE_POLLED_CSC) {
|
|||
|
//
|
|||
|
// Cancel the poll timer
|
|||
|
//
|
|||
|
KeCancelTimer(&fdoExtension->PollTimer);
|
|||
|
}
|
|||
|
|
|||
|
IoDetachDevice(fdoExtension->LowerDevice);
|
|||
|
nextFdo = fdoExtension->NextFdo;
|
|||
|
IoDeleteDevice(fdo);
|
|||
|
}
|
|||
|
}
|
|||
|
|