/** * PnP Request handler. * * @param pDevObj Device object. * @param pIrp Request packet. */ NTSTATUS vbgdNtPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp) { PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension; PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp); #ifdef LOG_ENABLED static char *s_apszFnctName[] = { "IRP_MN_START_DEVICE", "IRP_MN_QUERY_REMOVE_DEVICE", "IRP_MN_REMOVE_DEVICE", "IRP_MN_CANCEL_REMOVE_DEVICE", "IRP_MN_STOP_DEVICE", "IRP_MN_QUERY_STOP_DEVICE", "IRP_MN_CANCEL_STOP_DEVICE", "IRP_MN_QUERY_DEVICE_RELATIONS", "IRP_MN_QUERY_INTERFACE", "IRP_MN_QUERY_CAPABILITIES", "IRP_MN_QUERY_RESOURCES", "IRP_MN_QUERY_RESOURCE_REQUIREMENTS", "IRP_MN_QUERY_DEVICE_TEXT", "IRP_MN_FILTER_RESOURCE_REQUIREMENTS", "IRP_MN_0xE", "IRP_MN_READ_CONFIG", "IRP_MN_WRITE_CONFIG", "IRP_MN_EJECT", "IRP_MN_SET_LOCK", "IRP_MN_QUERY_ID", "IRP_MN_QUERY_PNP_DEVICE_STATE", "IRP_MN_QUERY_BUS_INFORMATION", "IRP_MN_DEVICE_USAGE_NOTIFICATION", "IRP_MN_SURPRISE_REMOVAL", }; Log(("VBoxGuest::vbgdNtGuestPnp: MinorFunction: %s\n", pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName) ? s_apszFnctName[pStack->MinorFunction] : "Unknown")); #endif NTSTATUS rc = STATUS_SUCCESS; switch (pStack->MinorFunction) { case IRP_MN_START_DEVICE: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE); if ( NT_SUCCESS(rc) && NT_SUCCESS(pIrp->IoStatus.Status)) { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n", pStack->Parameters.StartDevice.AllocatedResources)); if (!pStack->Parameters.StartDevice.AllocatedResources) { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n", pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL)); rc = STATUS_UNSUCCESSFUL; } else { rc = vbgdNtInit(pDevObj, pIrp); } } if (NT_ERROR(rc)) { Log(("VBoxGuest::vbgdNtGuestPnp: START_DEVICE: Error: rc = 0x%x\n", rc)); /* Need to unmap memory in case of errors ... */ vbgdNtUnmapVMMDevMemory(pDevExt); } break; } case IRP_MN_CANCEL_REMOVE_DEVICE: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_REMOVE_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE); if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGREMOVE) { /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */ pDevExt->devState = pDevExt->prevDevState; } /* Complete the IRP. */ break; } case IRP_MN_SURPRISE_REMOVAL: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: IRP_MN_SURPRISE_REMOVAL\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, SURPRISEREMOVED); /* Do nothing here actually. Cleanup is done in IRP_MN_REMOVE_DEVICE. * This request is not expected for VBoxGuest. */ LogRel(("VBoxGuest: unexpected device removal\n")); /* Pass to the lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); /* Do not complete the IRP. */ return rc; } case IRP_MN_QUERY_REMOVE_DEVICE: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_REMOVE_DEVICE\n")); #ifdef VBOX_REBOOT_ON_UNINSTALL Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n")); rc = STATUS_UNSUCCESSFUL; #endif if (NT_SUCCESS(rc)) { VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGREMOVE); /* This IRP passed down to lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); /* we must not do anything the IRP after doing IoSkip & CallDriver * since the driver below us will complete (or already have completed) the IRP. * I.e. just return the status we got from IoCallDriver */ return rc; } /* Complete the IRP on failure. */ break; } case IRP_MN_REMOVE_DEVICE: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: REMOVE_DEVICE\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, REMOVED); /* Free hardware resources. */ /** @todo this should actually free I/O ports, interrupts, etc. * Update/bird: vbgdNtCleanup actually does that... So, what's there to do? */ rc = vbgdNtCleanup(pDevObj); Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: vbgdNtCleanup rc = 0x%08X\n", rc)); /* * We need to send the remove down the stack before we detach, * but we don't need to wait for the completion of this operation * (and to register a completion routine). */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); IoDetachDevice(pDevExt->pNextLowerDriver); Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Removing device ...\n")); /* Destroy device extension and clean up everything else. */ VbgdCommonDeleteDevExt(&pDevExt->Core); /* Remove DOS device + symbolic link. */ UNICODE_STRING win32Name; RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS); IoDeleteSymbolicLink(&win32Name); Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Deleting device ...\n")); /* Last action: Delete our device! pDevObj is *not* failed * anymore after this call! */ IoDeleteDevice(pDevObj); Log(("VBoxGuest::vbgdNtGuestPnp: REMOVE_DEVICE: Device removed!\n")); /* Propagating rc from IoCallDriver. */ return rc; /* Make sure that we don't do anything below here anymore! */ } case IRP_MN_CANCEL_STOP_DEVICE: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: CANCEL_STOP_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vbgdNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE); if (NT_SUCCESS(rc) && pDevExt->devState == PENDINGSTOP) { /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */ pDevExt->devState = pDevExt->prevDevState; } /* Complete the IRP. */ break; } case IRP_MN_QUERY_STOP_DEVICE: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: QUERY_STOP_DEVICE\n")); #ifdef VBOX_REBOOT_ON_UNINSTALL Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n")); pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; #endif if (NT_SUCCESS(rc)) { VBOXGUEST_UPDATE_DEVSTATE(pDevExt, PENDINGSTOP); /* This IRP passed down to lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); Log(("VBoxGuest::vbgdNtGuestPnp: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); /* we must not do anything with the IRP after doing IoSkip & CallDriver * since the driver below us will complete (or already have completed) the IRP. * I.e. just return the status we got from IoCallDriver */ return rc; } /* Complete the IRP on failure. */ break; } case IRP_MN_STOP_DEVICE: { Log(("VBoxGuest::vbgdNtVBoxGuestPnP: STOP_DEVICE\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, STOPPED); /* Free hardware resources. */ /** @todo this should actually free I/O ports, interrupts, etc. * Update/bird: vbgdNtCleanup actually does that... So, what's there to do? */ rc = vbgdNtCleanup(pDevObj); Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc)); /* Pass to the lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); Log(("VBoxGuest::vbgdNtGuestPnp: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); return rc; } default: { IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); return rc; } } pIrp->IoStatus.Status = rc; IoCompleteRequest(pIrp, IO_NO_INCREMENT); Log(("VBoxGuest::vbgdNtGuestPnp: Returning with rc = 0x%x\n", rc)); return rc; }
NTSTATUS vboxguestwinInit(PDRIVER_OBJECT pDrvObj, PDEVICE_OBJECT pDevObj, PUNICODE_STRING pRegPath) #endif { PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension; #ifndef TARGET_NT4 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp); #endif Log(("VBoxGuest::vboxguestwinInit\n")); int rc = STATUS_SUCCESS; #ifdef TARGET_NT4 /* * Let's have a look at what our PCI adapter offers. */ Log(("VBoxGuest::vboxguestwinInit: Starting to scan PCI resources of VBoxGuest ...\n")); /* Assign the PCI resources. */ PCM_RESOURCE_LIST pResourceList = NULL; UNICODE_STRING classNameString; RtlInitUnicodeString(&classNameString, L"VBoxGuestAdapter"); rc = HalAssignSlotResources(pRegPath, &classNameString, pDrvObj, pDevObj, PCIBus, pDevExt->win.s.busNumber, pDevExt->win.s.slotNumber, &pResourceList); if (pResourceList && pResourceList->Count > 0) vboxguestwinShowDeviceResources(&pResourceList->List[0].PartialResourceList); if (NT_SUCCESS(rc)) rc = vboxguestwinScanPCIResourceList(pResourceList, pDevExt); #else if (pStack->Parameters.StartDevice.AllocatedResources->Count > 0) vboxguestwinShowDeviceResources(&pStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList); if (NT_SUCCESS(rc)) rc = vboxguestwinScanPCIResourceList(pStack->Parameters.StartDevice.AllocatedResourcesTranslated, pDevExt); #endif if (NT_SUCCESS(rc)) { /* * Map physical address of VMMDev memory into MMIO region * and init the common device extension bits. */ void *pvMMIOBase = NULL; uint32_t cbMMIO = 0; rc = vboxguestwinMapVMMDevMemory(pDevExt, pDevExt->win.s.vmmDevPhysMemoryAddress, pDevExt->win.s.vmmDevPhysMemoryLength, &pvMMIOBase, &cbMMIO); if (NT_SUCCESS(rc)) { pDevExt->pVMMDevMemory = (VMMDevMemory *)pvMMIOBase; Log(("VBoxGuest::vboxguestwinInit: pvMMIOBase = 0x%p, pDevExt = 0x%p, pDevExt->pVMMDevMemory = 0x%p\n", pvMMIOBase, pDevExt, pDevExt ? pDevExt->pVMMDevMemory : NULL)); int vrc = VBoxGuestInitDevExt(pDevExt, pDevExt->IOPortBase, pvMMIOBase, cbMMIO, vboxguestwinVersionToOSType(g_winVersion), VMMDEV_EVENT_MOUSE_POSITION_CHANGED); if (RT_FAILURE(vrc)) { Log(("VBoxGuest::vboxguestwinInit: Could not init device extension, rc = %Rrc!\n", vrc)); rc = STATUS_DEVICE_CONFIGURATION_ERROR; } } else Log(("VBoxGuest::vboxguestwinInit: Could not map physical address of VMMDev, rc = 0x%x!\n", rc)); } if (NT_SUCCESS(rc)) { int vrc = VbglGRAlloc((VMMDevRequestHeader **)&pDevExt->win.s.pPowerStateRequest, sizeof (VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus); if (RT_FAILURE(vrc)) { Log(("VBoxGuest::vboxguestwinInit: Alloc for pPowerStateRequest failed, rc = %Rrc\n", vrc)); rc = STATUS_UNSUCCESSFUL; } } if (NT_SUCCESS(rc)) { /* * Register DPC and ISR. */ Log(("VBoxGuest::vboxguestwinInit: Initializing DPC/ISR ...\n")); IoInitializeDpcRequest(pDevExt->win.s.pDeviceObject, vboxguestwinDpcHandler); #ifdef TARGET_NT4 ULONG uInterruptVector; KIRQL irqLevel; /* Get an interrupt vector. */ /* Only proceed if the device provides an interrupt. */ if ( pDevExt->win.s.interruptLevel || pDevExt->win.s.interruptVector) { Log(("VBoxGuest::vboxguestwinInit: Getting interrupt vector (HAL): Bus: %u, IRQL: %u, Vector: %u\n", pDevExt->win.s.busNumber, pDevExt->win.s.interruptLevel, pDevExt->win.s.interruptVector)); uInterruptVector = HalGetInterruptVector(PCIBus, pDevExt->win.s.busNumber, pDevExt->win.s.interruptLevel, pDevExt->win.s.interruptVector, &irqLevel, &pDevExt->win.s.interruptAffinity); Log(("VBoxGuest::vboxguestwinInit: HalGetInterruptVector returns vector %u\n", uInterruptVector)); if (uInterruptVector == 0) Log(("VBoxGuest::vboxguestwinInit: No interrupt vector found!\n")); } else Log(("VBoxGuest::vboxguestwinInit: Device does not provide an interrupt!\n")); #endif if (pDevExt->win.s.interruptVector) { Log(("VBoxGuest::vboxguestwinInit: Connecting interrupt ...\n")); rc = IoConnectInterrupt(&pDevExt->win.s.pInterruptObject, /* Out: interrupt object. */ (PKSERVICE_ROUTINE)vboxguestwinIsrHandler, /* Our ISR handler. */ pDevExt, /* Device context. */ NULL, /* Optional spinlock. */ #ifdef TARGET_NT4 uInterruptVector, /* Interrupt vector. */ irqLevel, /* Interrupt level. */ irqLevel, /* Interrupt level. */ #else pDevExt->win.s.interruptVector, /* Interrupt vector. */ (KIRQL)pDevExt->win.s.interruptLevel, /* Interrupt level. */ (KIRQL)pDevExt->win.s.interruptLevel, /* Interrupt level. */ #endif pDevExt->win.s.interruptMode, /* LevelSensitive or Latched. */ TRUE, /* Shareable interrupt. */ pDevExt->win.s.interruptAffinity, /* CPU affinity. */ FALSE); /* Don't save FPU stack. */ if (NT_ERROR(rc)) Log(("VBoxGuest::vboxguestwinInit: Could not connect interrupt, rc = 0x%x\n", rc)); } else Log(("VBoxGuest::vboxguestwinInit: No interrupt vector found!\n")); } #ifdef VBOX_WITH_HGCM Log(("VBoxGuest::vboxguestwinInit: Allocating kernel session data ...\n")); int vrc = VBoxGuestCreateKernelSession(pDevExt, &pDevExt->win.s.pKernelSession); if (RT_FAILURE(vrc)) { Log(("VBoxGuest::vboxguestwinInit: Failed to allocated kernel session data! rc = %Rrc\n", rc)); rc = STATUS_UNSUCCESSFUL; } #endif if (RT_SUCCESS(rc)) { ULONG ulValue = 0; NTSTATUS s = vboxguestwinRegistryReadDWORD(RTL_REGISTRY_SERVICES, L"VBoxGuest", L"LoggingEnabled", &ulValue); if (NT_SUCCESS(s)) { pDevExt->fLoggingEnabled = ulValue >= 0xFF; if (pDevExt->fLoggingEnabled) Log(("Logging to release log enabled (0x%x)", ulValue)); } /* Ready to rumble! */ Log(("VBoxGuest::vboxguestwinInit: Device is ready!\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, WORKING); } else { pDevExt->win.s.pInterruptObject = NULL; } Log(("VBoxGuest::vboxguestwinInit: Returned with rc = 0x%x\n", rc)); return rc; }