/*++ 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); } }