NTSTATUS CHCDController::HandlePnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStack; PCOMMON_DEVICE_EXTENSION DeviceExtension; PCM_RESOURCE_LIST RawResourceList; PCM_RESOURCE_LIST TranslatedResourceList; PDEVICE_RELATIONS DeviceRelations; NTSTATUS Status; // // get device extension // DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // PC_ASSERT(DeviceExtension->IsFDO); // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); switch(IoStack->MinorFunction) { case IRP_MN_START_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_START FDO\n", m_USBType); // // first start lower device object // Status = SyncForwardIrp(m_NextDeviceObject, Irp); if (NT_SUCCESS(Status)) { // // operation succeeded, lets start the device // RawResourceList = IoStack->Parameters.StartDevice.AllocatedResources; TranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated; if (m_Hardware) { // // start the hardware // Status = m_Hardware->PnpStart(RawResourceList, TranslatedResourceList); } // // enable symbolic link // Status = SetSymbolicLink(TRUE); } DPRINT("[%s] HandlePnp IRP_MN_START FDO: Status %x\n", m_USBType ,Status); break; } case IRP_MN_QUERY_DEVICE_RELATIONS: { DPRINT("[%s] HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", m_USBType, IoStack->Parameters.QueryDeviceRelations.Type); if (m_HubController == NULL) { // // create hub controller // Status = CreateHubController(&m_HubController); if (!NT_SUCCESS(Status)) { // // failed to create hub controller // break; } // // initialize hub controller // Status = m_HubController->Initialize(m_DriverObject, PHCDCONTROLLER(this), m_Hardware, TRUE, 0 /* FIXME*/); if (!NT_SUCCESS(Status)) { // // failed to initialize hub controller // break; } // // add reference to prevent it from getting deleting while hub driver adds / removes references // m_HubController->AddRef(); } if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations) { // // allocate device relations // DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); if (!DeviceRelations) { // // no memory // Status = STATUS_INSUFFICIENT_RESOURCES; break; } // // init device relations // DeviceRelations->Count = 1; Status = m_HubController->GetHubControllerDeviceObject(&DeviceRelations->Objects [0]); // // sanity check // PC_ASSERT(Status == STATUS_SUCCESS); ObReferenceObject(DeviceRelations->Objects [0]); // // store result // Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; Status = STATUS_SUCCESS; } else { // // not supported // Status = STATUS_NOT_SUPPORTED; } break; } case IRP_MN_STOP_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_STOP_DEVICE\n", m_USBType); if (m_Hardware) { // // stop the hardware // Status = m_Hardware->PnpStop(); } else { // // fake success // Status = STATUS_SUCCESS; } if (NT_SUCCESS(Status)) { // // stop lower device // Status = SyncForwardIrp(m_NextDeviceObject, Irp); } break; } case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: { #if 0 // // sure // Irp->IoStatus.Status = STATUS_SUCCESS; // // forward irp to next device object // IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(m_NextDeviceObject, Irp); #else DPRINT1("[%s] Denying controller removal due to reinitialization bugs\n", m_USBType); Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; #endif } case IRP_MN_REMOVE_DEVICE: { DPRINT("[%s] HandlePnp IRP_MN_REMOVE_DEVICE FDO\n", m_USBType); // // delete the symbolic link // SetSymbolicLink(FALSE); // // forward irp to next device object // IoSkipCurrentIrpStackLocation(Irp); IoCallDriver(m_NextDeviceObject, Irp); // // detach device from device stack // IoDetachDevice(m_NextDeviceObject); // // delete device // IoDeleteDevice(m_FunctionalDeviceObject); return STATUS_SUCCESS; } default: { // // forward irp to next device object // IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(m_NextDeviceObject, Irp); } } // // store result and complete request // Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }
NTSTATUS Ext2Flush (IN PEXT2_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_SUCCESS; PIRP Irp = NULL; PIO_STACK_LOCATION IrpSp = NULL; PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_FCBVCB FcbOrVcb = NULL; PEXT2_CCB Ccb = NULL; PFILE_OBJECT FileObject = NULL; PDEVICE_OBJECT DeviceObject = NULL; BOOLEAN MainResourceAcquired = FALSE; _SEH2_TRY { ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); DeviceObject = IrpContext->DeviceObject; // // This request is not allowed on the main device object // if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB))); ASSERT(IsMounted(Vcb)); if (IsVcbReadOnly(Vcb)) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); FileObject = IrpContext->FileObject; FcbOrVcb = (PEXT2_FCBVCB) FileObject->FsContext; ASSERT(FcbOrVcb != NULL); Ccb = (PEXT2_CCB) FileObject->FsContext2; if (Ccb == NULL) { Status = STATUS_SUCCESS; _SEH2_LEAVE; } MainResourceAcquired = ExAcquireResourceExclusiveLite(&FcbOrVcb->MainResource, TRUE); ASSERT(MainResourceAcquired); DEBUG(DL_INF, ("Ext2Flush-pre: total mcb records=%u\n", FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents))); if (FcbOrVcb->Identifier.Type == EXT2VCB) { Ext2VerifyVcb(IrpContext, Vcb); Status = Ext2FlushFiles(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE); if (NT_SUCCESS(Status)) { _SEH2_LEAVE; } Status = Ext2FlushVolume(IrpContext, (PEXT2_VCB)(FcbOrVcb), FALSE); if (NT_SUCCESS(Status) && IsFlagOn(Vcb->Volume->Flags, FO_FILE_MODIFIED)) { ClearFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); } } else if (FcbOrVcb->Identifier.Type == EXT2FCB) { Fcb = (PEXT2_FCB)(FcbOrVcb); Status = Ext2FlushFile(IrpContext, Fcb, Ccb); if (NT_SUCCESS(Status)) { if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) { Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE; ClearFlag(FileObject->Flags, FO_FILE_MODIFIED); } } } DEBUG(DL_INF, ("Ext2Flush-post: total mcb records=%u\n", FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents))); } _SEH2_FINALLY { if (MainResourceAcquired) { ExReleaseResourceLite(&FcbOrVcb->MainResource); } if (!IrpContext->ExceptionInProgress) { if (Vcb && Irp && IrpSp && !IsVcbReadOnly(Vcb)) { // Call the disk driver to flush the physial media. NTSTATUS DriverStatus; PIO_STACK_LOCATION NextIrpSp; NextIrpSp = IoGetNextIrpStackLocation(Irp); *NextIrpSp = *IrpSp; IoSetCompletionRoutine( Irp, Ext2FlushCompletionRoutine, NULL, TRUE, TRUE, TRUE ); DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp); Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ? Status : DriverStatus; IrpContext->Irp = Irp = NULL; } Ext2CompleteIrpContext(IrpContext, Status); } } _SEH2_END; return Status; }
NTSTATUS DokanSendIoContlToMountManager( __in PVOID InputBuffer, __in ULONG Length ) { NTSTATUS status; UNICODE_STRING mountManagerName; PFILE_OBJECT mountFileObject; PDEVICE_OBJECT mountDeviceObject; PIRP irp; KEVENT driverEvent; IO_STATUS_BLOCK iosb; DDbgPrint("=> DokanSnedIoContlToMountManager\n"); RtlInitUnicodeString(&mountManagerName, MOUNTMGR_DEVICE_NAME); status = IoGetDeviceObjectPointer( &mountManagerName, FILE_READ_ATTRIBUTES, &mountFileObject, &mountDeviceObject); if (!NT_SUCCESS(status)) { DDbgPrint(" IoGetDeviceObjectPointer failed: 0x%x\n", status); return status; } KeInitializeEvent(&driverEvent, NotificationEvent, FALSE); irp = IoBuildDeviceIoControlRequest( IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, mountDeviceObject, InputBuffer, Length, NULL, 0, FALSE, &driverEvent, &iosb); if (irp == NULL) { DDbgPrint(" IoBuildDeviceIoControlRequest failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } status = IoCallDriver(mountDeviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject( &driverEvent, Executive, KernelMode, FALSE, NULL); } status = iosb.Status; ObDereferenceObject(mountFileObject); ObDereferenceObject(mountDeviceObject); if (NT_SUCCESS(status)) { DDbgPrint(" IoCallDriver success\n"); } else { DDbgPrint(" IoCallDriver faield: 0x%x\n", status); } DDbgPrint("<= DokanSendIoContlToMountManager\n"); return status; }
NTSTATUS AFSCommonClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS ntStatus = STATUS_SUCCESS; ULONG ulRequestType = 0; IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); AFSDeviceExt *pDeviceExt = NULL; AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSDeviceObject->DeviceExtension; __Enter { pDeviceExt = (AFSDeviceExt *)DeviceObject->DeviceExtension; pIrpSp = IoGetCurrentIrpStackLocation( Irp); if( pIrpSp->FileObject->FsContext == NULL) { AFSCompleteRequest( Irp, ntStatus); try_return( ntStatus); } // // Check the state of the library // ntStatus = AFSCheckLibraryState( Irp); if( !NT_SUCCESS( ntStatus) || ntStatus == STATUS_PENDING) { if( ntStatus != STATUS_PENDING) { AFSCompleteRequest( Irp, ntStatus); } try_return( ntStatus); } IoSkipCurrentIrpStackLocation( Irp); ntStatus = IoCallDriver( pControlDeviceExt->Specific.Control.LibraryDeviceObject, Irp); // // Indicate the library is done with the request // AFSClearLibraryRequest(); try_exit: NOTHING; } return ntStatus; }
NTSTATUS Ext2DeviceControlNormal (IN PEXT2_IRP_CONTEXT IrpContext) { PDEVICE_OBJECT DeviceObject; BOOLEAN CompleteRequest = TRUE; NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb; PIRP Irp; PIO_STACK_LOCATION IrpSp; PIO_STACK_LOCATION NextIrpSp; PDEVICE_OBJECT TargetDeviceObject; _SEH2_TRY { ASSERT(IrpContext != NULL); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); CompleteRequest = TRUE; DeviceObject = IrpContext->DeviceObject; if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; } Irp = IrpContext->Irp; IrpSp = IoGetCurrentIrpStackLocation(Irp); Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext; if (!((Vcb) && (Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB)))) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } TargetDeviceObject = Vcb->TargetDeviceObject; // // Pass on the IOCTL to the driver below // CompleteRequest = FALSE; NextIrpSp = IoGetNextIrpStackLocation( Irp ); *NextIrpSp = *IrpSp; IoSetCompletionRoutine( Irp, Ext2DeviceControlCompletion, NULL, FALSE, TRUE, TRUE ); Status = IoCallDriver(TargetDeviceObject, Irp); } _SEH2_FINALLY { if (!IrpContext->ExceptionInProgress) { if (IrpContext) { if (!CompleteRequest) { IrpContext->Irp = NULL; } Ext2CompleteIrpContext(IrpContext, Status); } } } _SEH2_END; return Status; }
NTSTATUS Serenum_FDO_PnP ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION IrpStack, IN PFDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the PlugPlay system for the BUS itself NB: the various Minor functions of the PlugPlay system will not be overlapped and do not have to be reentrant --*/ { NTSTATUS status; KEVENT event; ULONG length; ULONG i; PDEVICE_RELATIONS relations; PIO_STACK_LOCATION stack; PRTL_QUERY_REGISTRY_TABLE QueryTable = NULL; ULONG DebugLevelDefault = SER_DEFAULT_DEBUG_OUTPUT_LEVEL; PAGED_CODE(); status = Serenum_IncIoCount (DeviceData); if (!NT_SUCCESS (status)) { Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } stack = IoGetCurrentIrpStackLocation (Irp); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // BEFORE you are allowed to ``touch'' the device object to which // the FDO is attached (that send an irp from the bus to the Device // object to which the bus is attached). You must first pass down // the start IRP. It might not be powered on, or able to access or // something. // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Start Device\n")); if (DeviceData->Started) { Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Device already started\n")); status = STATUS_SUCCESS; break; } KeInitializeEvent (&event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine (Irp, SerenumSyncCompletion, &event, TRUE, TRUE, TRUE); status = IoCallDriver (DeviceData->TopOfStack, Irp); if (STATUS_PENDING == status) { // wait for it... status = KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, // Not allertable NULL); // No timeout structure ASSERT (STATUS_SUCCESS == status); status = Irp->IoStatus.Status; } if (NT_SUCCESS(status)) { // // Now we can touch the lower device object as it is now started. // // // Get the debug level from the registry // if (NULL == (QueryTable = ExAllocatePool( PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE)*2 ))) { Serenum_KdPrint (DeviceData, SER_DBG_PNP_ERROR, ("Failed to allocate memory to query registy\n")); DeviceData->DebugLevel = DebugLevelDefault; } else { RtlZeroMemory( QueryTable, sizeof(RTL_QUERY_REGISTRY_TABLE)*2 ); QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[0].EntryContext = &DeviceData->DebugLevel; QueryTable[0].Name = L"DebugLevel"; QueryTable[0].DefaultType = REG_DWORD; QueryTable[0].DefaultData = &DebugLevelDefault; QueryTable[0].DefaultLength= sizeof(ULONG); // CIMEXCIMEX: The rest of the table isn't filled in! if (!NT_SUCCESS(RtlQueryRegistryValues( RTL_REGISTRY_SERVICES, L"Serenum", QueryTable, NULL, NULL))) { Serenum_KdPrint (DeviceData,SER_DBG_PNP_ERROR, ("Failed to get debug level from registry. " "Using default\n")); DeviceData->DebugLevel = DebugLevelDefault; } ExFreePool( QueryTable ); } Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Start Device: Device started successfully\n")); DeviceData->Started = TRUE; } // // We must now complete the IRP, since we stopped it in the // completetion routine with MORE_PROCESSING_REQUIRED. // break; case IRP_MN_QUERY_STOP_DEVICE: Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Stop Device\n")); // // Test to see if there are any PDO created as children of this FDO // If there are then conclude the device is busy and fail the // query stop. // // CIMEXCIMEX // We could do better, by seing if the children PDOs are actually // currently open. If they are not then we could stop, get new // resouces, fill in the new resouce values, and then when a new client // opens the PDO use the new resources. But this works for now. // if (DeviceData->AttachedPDO || (DeviceData->EnumFlags & SERENUM_ENUMFLAG_PENDING)) { status = STATUS_UNSUCCESSFUL; } else { status = STATUS_SUCCESS; } Irp->IoStatus.Status = status; if (NT_SUCCESS(status)) { IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); } else { IoCompleteRequest(Irp, IO_NO_INCREMENT); } Serenum_DecIoCount (DeviceData); return status; case IRP_MN_CANCEL_STOP_DEVICE: // // We always succeed a cancel stop // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Cancel Stop Device\n")); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_STOP_DEVICE: Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Stop Device\n")); // // Wait for the enum thread to complete if it's running // SerenumWaitForEnumThreadTerminate(DeviceData); // // After the start IRP has been sent to the lower driver object, the // bus may NOT send any more IRPS down ``touch'' until another START // has occured. // What ever access is required must be done before the Irp is passed // on. // // Stop device means that the resources given durring Start device // are no revoked. So we need to stop using them // DeviceData->Started = FALSE; // // We don't need a completion routine so fire and forget. // // Set the current stack location to the next stack location and // call the next device object. // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_REMOVE_DEVICE: Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Remove Device\n")); // // The PlugPlay system has detected the removal of this device. We // have no choice but to detach and delete the device object. // (If we wanted to express and interest in preventing this removal, // we should have filtered the query remove and query stop routines.) // // Note! we might receive a remove WITHOUT first receiving a stop. // ASSERT (!DeviceData->Removed); // // Synchronize with the enum thread if it is running and wait // for it to finish // SerenumWaitForEnumThreadTerminate(DeviceData); // We will accept no new requests // DeviceData->Removed = TRUE; // // Complete any outstanding IRPs queued by the driver here. // // // Make the DCA go away. Some drivers may choose to remove the DCA // when they receive a stop or even a query stop. We just don't care. // (void)IoSetDeviceInterfaceState (&DeviceData->DevClassAssocName, FALSE); // // Here if we had any outstanding requests in a personal queue we should // complete them all now. // // Note, the device is guarenteed stopped, so we cannot send it any non- // PNP IRPS. // // // Fire and forget // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); // // Wait for any outstanding threads to complete // // // Wait for all outstanding requests to complete // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Waiting for outstanding requests\n")); i = InterlockedDecrement ((volatile LONG*)&DeviceData->OutstandingIO); ASSERT (0 < i); if (0 != InterlockedDecrement ((volatile LONG*)&DeviceData->OutstandingIO)) { Serenum_KdPrint (DeviceData, SER_DBG_PNP_INFO, ("Remove Device waiting for request to complete\n")); KeWaitForSingleObject (&DeviceData->RemoveEvent, Executive, KernelMode, FALSE, // Not Alertable NULL); // No timeout } // // Free the associated resources // // // Detach from the underlying devices. // Serenum_KdPrint(DeviceData, SER_DBG_PNP_INFO, ("IoDetachDevice: 0x%x\n", DeviceData->TopOfStack)); IoDetachDevice (DeviceData->TopOfStack); // // Clean up any resources here // ExFreePool (DeviceData->DevClassAssocName.Buffer); Serenum_KdPrint(DeviceData, SER_DBG_PNP_INFO, ("IoDeleteDevice: 0x%x\n", DeviceObject)); // // Remove any PDO's we ejected // if (DeviceData->AttachedPDO != NULL) { ASSERT(DeviceData->NumPDOs == 1); Serenum_PnPRemove(DeviceData->AttachedPDO, DeviceData->PdoData); DeviceData->PdoData = NULL; DeviceData->AttachedPDO = NULL; DeviceData->NumPDOs = 0; } IoDeleteDevice(DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support this // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Device Relations - Non bus\n")); goto SER_FDO_PNP_DEFAULT; } Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Bus Relations\n")); status = SerenumCheckEnumerations(DeviceData); // // Tell the plug and play system about all the PDOs. // // There might also be device relations below and above this FDO, // so, be sure to propagate the relations from the upper drivers. // // No Completion routine is needed so long as the status is preset // to success. (PDOs complete plug and play irps with the current // IoStatus.Status and IoStatus.Information as the default.) // //KeAcquireSpinLock (&DeviceData->Spin, &oldIrq); i = (0 == Irp->IoStatus.Information) ? 0 : ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Count; // The current number of PDOs in the device relations structure Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("#PDOS = %d + %d\n", i, DeviceData->NumPDOs)); length = sizeof(DEVICE_RELATIONS) + ((DeviceData->NumPDOs + i) * sizeof (PDEVICE_OBJECT)); relations = (PDEVICE_RELATIONS) ExAllocatePool (NonPagedPool, length); if (NULL == relations) { Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); Serenum_DecIoCount(DeviceData); return STATUS_INSUFFICIENT_RESOURCES; } // // Copy in the device objects so far // if (i) { RtlCopyMemory ( relations->Objects, ((PDEVICE_RELATIONS) Irp->IoStatus.Information)->Objects, i * sizeof (PDEVICE_OBJECT)); } relations->Count = DeviceData->NumPDOs + i; // // For each PDO on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The PlugPlay system will dereference the object when it is done with // it and free the device relations buffer. // if (DeviceData->NumPDOs) { relations->Objects[relations->Count-1] = DeviceData->AttachedPDO; ObReferenceObject (DeviceData->AttachedPDO); } // // Set up and pass the IRP further down the stack // Irp->IoStatus.Status = STATUS_SUCCESS; if (0 != Irp->IoStatus.Information) { ExFreePool ((PVOID) Irp->IoStatus.Information); } Irp->IoStatus.Information = (ULONG_PTR)relations; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_REMOVE_DEVICE: // // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Query Remove Device\n")); // // Wait for the enum thread to complete if it's running // SerenumWaitForEnumThreadTerminate(DeviceData); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_CAPABILITIES: { PIO_STACK_LOCATION irpSp; // // Send this down to the PDO first // KeInitializeEvent (&event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext (Irp); IoSetCompletionRoutine (Irp, SerenumSyncCompletion, &event, TRUE, TRUE, TRUE); status = IoCallDriver (DeviceData->TopOfStack, Irp); if (STATUS_PENDING == status) { // wait for it... status = KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, // Not allertable NULL); // No timeout structure ASSERT (STATUS_SUCCESS == status); status = Irp->IoStatus.Status; } if (NT_SUCCESS(status)) { irpSp = IoGetCurrentIrpStackLocation(Irp); DeviceData->SystemWake = irpSp->Parameters.DeviceCapabilities.Capabilities->SystemWake; DeviceData->DeviceWake = irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceWake; } break; } SER_FDO_PNP_DEFAULT: default: // // In the default case we merely call the next driver since // we don't know what to do. // Serenum_KdPrint (DeviceData, SER_DBG_PNP_TRACE, ("Default Case\n")); // // Fire and Forget // IoSkipCurrentIrpStackLocation (Irp); // // Done, do NOT complete the IRP, it will be processed by the lower // device object, which will complete the IRP // status = IoCallDriver (DeviceData->TopOfStack, Irp); Serenum_DecIoCount (DeviceData); return status; } Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Serenum_DecIoCount (DeviceData); return status; }
NTSTATUS NdasFatCommonFlushBuffers ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for flushing a buffer. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PCCB Ccb; BOOLEAN VcbAcquired = FALSE; BOOLEAN FcbAcquired = FALSE; PDIRENT Dirent; PBCB DirentBcb = NULL; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; PAGED_CODE(); IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject); // // Extract and decode the file object // FileObject = IrpSp->FileObject; TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); // // CcFlushCache is always synchronous, so if we can't wait enqueue // the irp to the Fsp. // if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) { Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status ); return Status; } Status = STATUS_SUCCESS; try { if (!FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { do { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); NDAS_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); if (secondaryRequest == NULL) { NDAS_ASSERT( NDAS_ASSERT_INSUFFICIENT_RESOURCES ); Status = STATUS_INSUFFICIENT_RESOURCES; break; } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, IrpContext->OriginatingIrp, IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp), Ccb->PrimaryFileHandle ); ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (Status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); break; } KeClearEvent (&secondaryRequest->CompleteEvent); if (BooleanFlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { NDAS_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) { ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; ASSERT(NTOHL(ndfsWinxpReplytHeader->Status4) == STATUS_SUCCESS); } if (secondaryRequest) { DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } if ( secondarySessionResourceAcquired == TRUE ) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); secondarySessionResourceAcquired = FALSE; } break; } while(0); } Status = STATUS_SUCCESS; // // Case on the type of open that we are trying to flush // switch (TypeOfOpen) { case VirtualVolumeFile: case EaFile: case DirectoryFile: DebugTrace(0, Dbg, "Flush that does nothing\n", 0); break; case UserFileOpen: DebugTrace(0, Dbg, "Flush User File Open\n", 0); (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); FcbAcquired = TRUE; FatVerifyFcb( IrpContext, Fcb ); // // If the file is cached then flush its cache // Status = FatFlushFile( IrpContext, Fcb, Flush ); // // Also update and flush the file's dirent in the parent directory if the // file flush worked. // if (NT_SUCCESS( Status )) { // // Insure that we get the filesize to disk correctly. This is // benign if it was already good. // // (why do we need to do this?) // SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED); #if 0 FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); #endif // // Flush the volume file to get any allocation information // updates to disk. // if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) { Status = FatFlushFat( IrpContext, Vcb ); ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT); } // // Set the write through bit so that these modifications // will be completed with the request. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH); } break; case UserDirectoryOpen: // // If the user had opened the root directory then we'll // oblige by flushing the volume. // if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) { DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0); break; } case UserVolumeOpen: DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0); // // Acquire exclusive access to the Vcb. // { BOOLEAN Finished; Finished = FatAcquireExclusiveVcb( IrpContext, Vcb ); ASSERT( Finished ); } VcbAcquired = TRUE; // // Mark the volume clean and then flush the volume file, // and then all directories // Status = FatFlushVolume( IrpContext, Vcb, Flush ); // // If the volume was dirty, do the processing that the delayed // callback would have done. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) { // // Cancel any pending clean volumes. // (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer ); (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc ); // // The volume is now clean, note it. // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { FatMarkVolume( IrpContext, Vcb, VolumeClean ); ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); } // // Unlock the volume if it is removable. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) { FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE ); } } break; default: FatBugCheck( TypeOfOpen, 0, 0 ); } FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinRepinnedBcbs( IrpContext ); } finally { DebugUnwind( FatCommonFlushBuffers ); if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); if (secondarySessionResourceAcquired) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); } FatUnpinBcb( IrpContext, DirentBcb ); if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); } if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); } // // If this is a normal termination then pass the request on // to the target device object. // if (!AbnormalTermination()) { NTSTATUS DriverStatus; PIO_STACK_LOCATION NextIrpSp; // // Get the next stack location, and copy over the stack location // NextIrpSp = IoGetNextIrpStackLocation( Irp ); *NextIrpSp = *IrpSp; // // Set up the completion routine // IoSetCompletionRoutine( Irp, FatFlushCompletionRoutine, ULongToPtr( Status ), TRUE, TRUE, TRUE ); // // Send the request. // DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp); Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ? Status : DriverStatus; // // Free the IrpContext and return to the caller. // FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS ); } DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status); } return Status; }
NTSTATUS TcpTdiListenWithCompletionEvent( IN PFILE_OBJECT ConnectionFileObject, IN PTCP_TDI_LISTEN_CONTEXT TdiListenContext, IN PULONG Flags ) { PDEVICE_OBJECT deviceObject; PIRP irp; NTSTATUS ntStatus; TCPLtDebugPrint (1, ("[TcpTdi]TcpTdiListen: Entered.\n")); // // Make Event. // //KeInitializeEvent(&event, NotificationEvent, FALSE); deviceObject = IoGetRelatedDeviceObject(ConnectionFileObject); // // Make IRP. // irp = TdiBuildInternalDeviceControlIrp( TDI_LISTEN, deviceObject, ConnectionFileObject, NULL, NULL ); if(irp == NULL) { TCPLtDebugPrint(1, ("[TcpTdi]TcpTdiListen: Can't Build IRP.\n")); return STATUS_INSUFFICIENT_RESOURCES; } TdiListenContext->RequestConnectionInfo.UserData = NULL ; TdiListenContext->RequestConnectionInfo.UserDataLength = 0 ; TdiListenContext->RequestConnectionInfo.Options = Flags ; TdiListenContext->RequestConnectionInfo.OptionsLength = sizeof(ULONG) ; TdiListenContext->RequestConnectionInfo.RemoteAddress = NULL ; TdiListenContext->RequestConnectionInfo.RemoteAddressLength = 0 ; TdiListenContext->ReturnConnectionInfo.UserData = NULL ; TdiListenContext->ReturnConnectionInfo.UserDataLength = 0 ; TdiListenContext->ReturnConnectionInfo.Options = Flags ; TdiListenContext->ReturnConnectionInfo.OptionsLength = sizeof(ULONG) ; TdiListenContext->ReturnConnectionInfo.RemoteAddress = TdiListenContext->AddressBuffer ; TdiListenContext->ReturnConnectionInfo.RemoteAddressLength = TPADDR_IP_LENGTH ; TdiBuildListen( irp, deviceObject, ConnectionFileObject, TcpTdiListenCompletionRoutine, TdiListenContext, *Flags, &TdiListenContext->RequestConnectionInfo, &TdiListenContext->ReturnConnectionInfo ); ntStatus = IoCallDriver( deviceObject, irp ); if(!NT_SUCCESS(ntStatus)) { TdiListenContext->Irp = NULL; TCPLtDebugPrint(1, ("[TcpTdi]TcpTdiListen: Failed.\n")); return ntStatus; } TdiListenContext->Irp = irp; return ntStatus; }
NTSTATUS TcpTdiRecvWithCompletionEvent( IN PFILE_OBJECT ConnectionFileObject, IN PTCP_TDI_RECEIVE_CONTEXT TdiReceiveContext, OUT PUCHAR RecvBuffer, IN ULONG RecvLength, IN ULONG Flags ) { PDEVICE_OBJECT deviceObject; PIRP irp; NTSTATUS ntStatus; PMDL mdl; ASSERT(ConnectionFileObject); TCPLtDebugPrint (3, ("TcpTdiRecvWithCompletionEvent: Entered\n")); if((RecvBuffer == NULL) || (RecvLength == 0)) { TCPLtDebugPrint(1, ("[TcpTdi]TdiReceive: Rcv buffer == NULL or RcvLen == 0.\n")); return STATUS_NOT_IMPLEMENTED; } deviceObject = IoGetRelatedDeviceObject(ConnectionFileObject); // // Make IRP. // irp = TdiBuildInternalDeviceControlIrp( TDI_RECEIVE, deviceObject, connectionFileObject, NULL, NULL ); if(irp == NULL) { TCPLtDebugPrint(1, ("[TcpTdi]TdiReceive: Can't Build IRP.\n")); return STATUS_INSUFFICIENT_RESOURCES; } mdl = IoAllocateMdl( RecvBuffer, RecvLength, FALSE, FALSE, irp ); if(mdl == NULL) { TCPLtDebugPrint(1, ("[TcpTdi]TdiReceive: Can't Allocate MDL.\n")); IoFreeIrp(irp); return STATUS_INSUFFICIENT_RESOURCES; } mdl->Next = NULL; MmBuildMdlForNonPagedPool(mdl); TdiBuildReceive( irp, deviceObject, ConnectionFileObject, TcpTdiRecvWithCompletionEventCompletionRoutine, TdiReceiveContext, mdl, Flags, RecvLength ); // SET_IRP_EXPTIME(irp, CurrentTime().QuadPart + TDI_TIME_OUT); // SET_IRP_EXPTIME(irp, 0); ntStatus = IoCallDriver( deviceObject, irp ); if(!NT_SUCCESS(ntStatus)) { TdiReceiveContext->Irp = NULL; TCPLtDebugPrint(1, ("[TcpTdi]TcpTdiRecv: Failed.\n")); return ntStatus; } TdiReceiveContext->Irp = irp; return ntStatus; }
NTSTATUS DPQueryVolumeInformation( PDEVICE_OBJECT DevObj, LARGE_INTEGER * TotalSize, DWORD * ClusterSize, DWORD * SectorSize ) { #define _FileSystemNameLength 64 //定义FAT16文件系统签名的偏移量 #define FAT16_SIG_OFFSET 54 //定义FAT32文件系统签名的偏移量 #define FAT32_SIG_OFFSET 82 //定义NTFS文件系统签名的偏移量 #define NTFS_SIG_OFFSET 3 //这是FAT16文件系统的标志 const UCHAR FAT16FLG[4] = {'F','A','T','1'}; //这是FAT32文件系统的标志 const UCHAR FAT32FLG[4] = {'F','A','T','3'}; //这是NTFS文件系统的标志 const UCHAR NTFSFLG[4] = {'N','T','F','S'}; //返回值 NTSTATUS ntStatus = STATUS_SUCCESS; //用来读取卷DBR扇区的数据缓冲区 BYTE DBR[512] = { 0 }; //DBR扇区有512个bytes大小 ULONG DBRLength = 512; //以下是三个指针,统一指向读取的DBR数据,但是这三个指针的类型分别代表FAT16,FAT32和NTFS类型文件系统的DBR数据结构 PDP_NTFS_BOOT_SECTOR pNtfsBootSector = (PDP_NTFS_BOOT_SECTOR)DBR; PDP_FAT32_BOOT_SECTOR pFat32BootSector = (PDP_FAT32_BOOT_SECTOR)DBR; PDP_FAT16_BOOT_SECTOR pFat16BootSector = (PDP_FAT16_BOOT_SECTOR)DBR; //读取的偏移量,对于DBR来说是卷的起始位置,所以偏移量为0 LARGE_INTEGER readOffset = { 0 }; //读取时的io操作状态 IO_STATUS_BLOCK ios; //为了同步读取所设置的同步事件 KEVENT Event; //为了同步读取所需要构建的irp指针 PIRP pIrp = NULL; //下面我们首先从指定的卷设备上读取偏移量为0的一个扇区,也就是这个卷的DBR扇区,准备加以分析 //因为我们要同步读取,所以先初始化一个为了同步读取设置的事件 KeInitializeEvent(&Event, NotificationEvent, FALSE); //构造一个irp用来发给卷设备来读取信息 pIrp = IoBuildAsynchronousFsdRequest( IRP_MJ_READ, DevObj, DBR, DBRLength, &readOffset, &ios ); if (NULL == pIrp) { goto ERROUT; } //设置完成函数,并且将同步事件作为完成函数的参数传入 IoSetCompletionRoutine( pIrp, DPQueryVolumeInformationCompletionRoutine, &Event, TRUE, TRUE, TRUE ); //调用目标设备去处理这个irp ntStatus = IoCallDriver(DevObj, pIrp); if(ntStatus = STATUS_PENDING) { //如果下层设备一时不能完成这个irp请求,我们就等 ntStatus = KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL ); //将返回值设置为这个io操作的状态 ntStatus = pIrp->IoStatus.Status; if (!NT_SUCCESS(ntStatus)) { goto ERROUT; } } if (*(DWORD*)NTFSFLG == *(DWORD*)&DBR[NTFS_SIG_OFFSET]) { //通过比较标志发现这个卷是一个ntfs文件系统的卷,下面根据ntfs卷的DBR定义来对各种需要获取的值进行赋值操作 *SectorSize = (DWORD)(pNtfsBootSector->BytesPerSector); *ClusterSize = (*SectorSize) * (DWORD)(pNtfsBootSector->SectorsPerCluster); TotalSize->QuadPart = (LONGLONG)(*SectorSize) * (LONGLONG)pNtfsBootSector->TotalSectors; } else if (*(DWORD*)FAT32FLG == *(DWORD*)&DBR[FAT32_SIG_OFFSET]) { //通过比较标志发现这个卷是一个ntfs文件系统的卷,下面根据ntfs卷的DBR定义来对各种需要获取的值进行赋值操作 *SectorSize = (DWORD)(pFat32BootSector->BytesPerSector); *ClusterSize = (*SectorSize) * (DWORD)(pFat32BootSector->SectorsPerCluster); TotalSize->QuadPart = (LONGLONG)(*SectorSize) * (LONGLONG)(pFat32BootSector->LargeSectors + pFat32BootSector->Sectors); } else if (*(DWORD*)FAT16FLG == *(DWORD*)&DBR[FAT16_SIG_OFFSET]) { //通过比较标志发现这个卷是一个ntfs文件系统的卷,下面根据ntfs卷的DBR定义来对各种需要获取的值进行赋值操作 *SectorSize = (DWORD)(pFat16BootSector->BytesPerSector); *ClusterSize = (*SectorSize) * (DWORD)(pFat16BootSector->SectorsPerCluster); TotalSize->QuadPart = (LONGLONG)(*SectorSize) * (LONGLONG)(pFat16BootSector->LargeSectors + pFat16BootSector->Sectors); } else { //走到这里,可能是其它任何文件系统,但是不是windows认识的文件系统,我们统一返回错 ntStatus = STATUS_UNSUCCESSFUL; } ERROUT: if (NULL != pIrp) { IoFreeIrp(pIrp); } return ntStatus; }
NTSTATUS DCamSubmitIrpSynch( PDCAM_EXTENSION pDevExt, PIRP pIrp, PIRB pIrb ) /*++ Routine Description: This routine submits an Irp synchronously to the bus driver. We'll wait here til the Irp comes back Arguments: pDevExt - Pointer to my local device extension pIrp - Pointer to Irp we're sending down to the port driver synchronously pIrb - Pointer to Irb we're submitting to the port driver Return Value: Status is returned from Irp --*/ { LONG Retries=RETRY_COUNT_IRP_SYNC; // Take the worst case of 20 * 100 msec = 1sec KEVENT Event; NTSTATUS status; LARGE_INTEGER deltaTime; PIO_STACK_LOCATION NextIrpStack; BOOL bCanWait = KeGetCurrentIrql() < DISPATCH_LEVEL; BOOL bRetryStatus; PIRB pIrbRetry; NTSTATUS StatusRetry; ULONG ulGeneration; do { NextIrpStack = IoGetNextIrpStackLocation(pIrp); NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS; NextIrpStack->Parameters.Others.Argument1 = pIrb; KeInitializeEvent(&Event, SynchronizationEvent, FALSE); IoSetCompletionRoutine( pIrp, DCamSynchCR, &Event, TRUE, TRUE, TRUE ); status = IoCallDriver( pDevExt->BusDeviceObject, pIrp ); DbgMsg3(("\'DCamSubmitIrpSynch: pIrp is pending(%s); will wait(%s)\n", status == STATUS_PENDING?"Y":"N", bCanWait?"Y":"N")); if (bCanWait && status == STATUS_PENDING) { // // Still pending, wait for the IRP to complete // KeWaitForSingleObject( // Only in <= IRQL_DISPATCH_LEVEL; can only in DISPATCH if Timeout is 0 &Event, Executive, KernelMode, FALSE, NULL ); } // Will retry for any of these return status codes. bRetryStatus = pIrp->IoStatus.Status == STATUS_TIMEOUT || pIrp->IoStatus.Status == STATUS_IO_TIMEOUT || pIrp->IoStatus.Status == STATUS_DEVICE_BUSY || pIrp->IoStatus.Status == STATUS_INVALID_GENERATION; if (bCanWait && bRetryStatus && Retries > 0) { // Camera isn't fast enough to respond so delay this thread and try again. switch(pIrp->IoStatus.Status) { case STATUS_TIMEOUT: case STATUS_IO_TIMEOUT: case STATUS_DEVICE_BUSY: deltaTime.LowPart = DCAM_DELAY_VALUE; deltaTime.HighPart = -1; KeDelayExecutionThread(KernelMode, TRUE, &deltaTime); break; case STATUS_INVALID_GENERATION: // Cache obsolete ulGeneration and use it to detect its udpate in busreset callback. if(pIrb->FunctionNumber == REQUEST_ASYNC_READ) ulGeneration = pIrb->u.AsyncRead.ulGeneration; else if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE) ulGeneration = pIrb->u.AsyncWrite.ulGeneration; else if(pIrb->FunctionNumber == REQUEST_ASYNC_LOCK) ulGeneration = pIrb->u.AsyncLock.ulGeneration; else if(pIrb->FunctionNumber == REQUEST_ISOCH_FREE_BANDWIDTH) { ERROR_LOG(("InvGen when free BW\n")); // Special case that we do not need to retry since BW should be free // and 1394 bus should just free the BW structure. Retries = 0; // no more retry and exit. break; } else { // Other REQUEST_* that depends on ulGeneration ERROR_LOG(("Unexpected IRB function with InvGen:%d\n", pIrb->FunctionNumber)); ASSERT(FALSE && "New REQUEST that requires ulGeneration"); Retries = 0; // do not know what to do so no more retry and exit. break; } pIrbRetry = ExAllocatePoolWithTag(NonPagedPool, sizeof(IRB), 'macd'); if (pIrbRetry) { deltaTime.LowPart = DCAM_DELAY_VALUE_BUSRESET; // Longer than the regular delay deltaTime.HighPart = -1; do { KeDelayExecutionThread(KernelMode, TRUE, &deltaTime); pIrbRetry->FunctionNumber = REQUEST_GET_GENERATION_COUNT; pIrbRetry->u.GetGenerationCount.GenerationCount = 0; pIrbRetry->Flags = 0; StatusRetry = DCamSubmitIrpSynch(pDevExt, pIrp, pIrbRetry); // Recursive with differnt IRB but same IRP. if(NT_SUCCESS(StatusRetry) && pIrbRetry->u.GetGenerationCount.GenerationCount > ulGeneration) { InterlockedExchange((PLONG)&pDevExt->CurrentGeneration, pIrbRetry->u.GetGenerationCount.GenerationCount); // Update the generation count for the original IRB request and try again. if(pIrb->FunctionNumber == REQUEST_ASYNC_READ) InterlockedExchange((PLONG)&pIrb->u.AsyncRead.ulGeneration, pDevExt->CurrentGeneration); else if(pIrb->FunctionNumber == REQUEST_ASYNC_WRITE) InterlockedExchange((PLONG)&pIrb->u.AsyncWrite.ulGeneration, pDevExt->CurrentGeneration); else if(pIrb->FunctionNumber == REQUEST_ASYNC_LOCK) InterlockedExchange((PLONG)&pIrb->u.AsyncLock.ulGeneration, pDevExt->CurrentGeneration); else { // Other (new) REQUEST_* that depends on ulGeneration } } if(Retries) Retries--; } while (Retries && ulGeneration >= pDevExt->CurrentGeneration); ERROR_LOG(("(%d) IrpSync: StautsRetry %x; Generation %d -> %d\n", Retries, StatusRetry, ulGeneration, pDevExt->CurrentGeneration)); ExFreePool(pIrbRetry); pIrbRetry = 0; } // if break; // All other status default: break; } } if(Retries) Retries--; } while (bCanWait && bRetryStatus && (Retries > 0)); #if DBG if(!NT_SUCCESS(pIrp->IoStatus.Status)) { ERROR_LOG(("IrpSynch: IoCallDriver Status:%x; pIrp->IoStatus.Status (final):%x; Wait:%d; Retries:%d\n", status, pIrp->IoStatus.Status, bCanWait, Retries)); } #endif return (pIrp->IoStatus.Status); }
NTSTATUS PciDrvSystemControl ( PDEVICE_OBJECT DeviceObject, PIRP Irp ) /*++ Routine Description We have just received a System Control IRP. Assume that this is a WMI IRP and call into the WMI system library and let it handle this IRP for us. --*/ { PFDO_DATA fdoData; SYSCTL_IRP_DISPOSITION disposition; NTSTATUS status; PIO_STACK_LOCATION stack; PAGED_CODE(); stack = IoGetCurrentIrpStackLocation (Irp); DebugPrint(TRACE, DBG_WMI, "FDO %s\n", WMIMinorFunctionString(stack->MinorFunction)); fdoData = (PFDO_DATA) DeviceObject->DeviceExtension; PciDrvPowerUpDevice(fdoData, TRUE); PciDrvIoIncrement (fdoData); if (fdoData->DevicePnPState == Deleted) { Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE; IoCompleteRequest (Irp, IO_NO_INCREMENT); PciDrvIoDecrement (fdoData); return status; } status = WmiSystemControl(&fdoData->WmiLibInfo, DeviceObject, Irp, &disposition); // // Following code is required if we want to do tracing in WIN2K. // Tracing is enabled or disabled explicitly by sending WMI // control events on Win2K. // #if defined(WIN2K) && defined(EVENT_TRACING) if (disposition != IrpProcessed && DeviceObject == (PDEVICE_OBJECT)stack->Parameters.WMI.ProviderId) { ULONG returnSize = 0; DebugPrint(INFO, DBG_WMI, "Calling WPP_TRACE_CONTROL\n"); WPP_TRACE_CONTROL(stack->MinorFunction, stack->Parameters.WMI.Buffer, stack->Parameters.WMI.BufferSize, returnSize); } #endif switch(disposition) { case IrpProcessed: { // // This irp has been processed and may be completed or pending. break; } case IrpNotCompleted: { // // This irp has not been completed, but has been fully processed. // we will complete it now IoCompleteRequest(Irp, IO_NO_INCREMENT); break; } case IrpForward: case IrpNotWmi: { // // This irp is either not a WMI irp or is a WMI irp targeted // at a device lower in the stack. IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (fdoData->NextLowerDriver, Irp); break; } default: { // // We really should never get here, but if we do just forward.... ASSERT(FALSE); IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (fdoData->NextLowerDriver, Irp); break; } } PciDrvIoDecrement(fdoData); return(status); }