RT_C_DECLS_END #ifdef ALLOC_PRAGMA # pragma alloc_text(INIT, vgdrvNt4CreateDevice) # pragma alloc_text(INIT, vgdrvNt4FindPciDevice) #endif /** * Legacy helper function to create the device object. * * @returns NT status code. * * @param pDrvObj The driver object. * @param pRegPath The driver registry path. */ NTSTATUS vgdrvNt4CreateDevice(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath) { Log(("vgdrvNt4CreateDevice: pDrvObj=%p, pRegPath=%p\n", pDrvObj, pRegPath)); /* * Find our virtual PCI device */ ULONG uBusNumber; PCI_SLOT_NUMBER SlotNumber; NTSTATUS rc = vgdrvNt4FindPciDevice(&uBusNumber, &SlotNumber); if (NT_ERROR(rc)) { Log(("vgdrvNt4CreateDevice: Device not found!\n")); return rc; } /* * Create device. */ UNICODE_STRING szDevName; RtlInitUnicodeString(&szDevName, VBOXGUEST_DEVICE_NAME_NT); PDEVICE_OBJECT pDeviceObject = NULL; rc = IoCreateDevice(pDrvObj, sizeof(VBOXGUESTDEVEXTWIN), &szDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject); if (NT_SUCCESS(rc)) { Log(("vgdrvNt4CreateDevice: Device created\n")); UNICODE_STRING DosName; RtlInitUnicodeString(&DosName, VBOXGUEST_DEVICE_NAME_DOS); rc = IoCreateSymbolicLink(&DosName, &szDevName); if (NT_SUCCESS(rc)) { Log(("vgdrvNt4CreateDevice: Symlink created\n")); /* * Setup the device extension. */ Log(("vgdrvNt4CreateDevice: Setting up device extension ...\n")); PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDeviceObject->DeviceExtension; RT_ZERO(*pDevExt); Log(("vgdrvNt4CreateDevice: Device extension created\n")); /* Store a reference to ourself. */ pDevExt->pDeviceObject = pDeviceObject; /* Store bus and slot number we've queried before. */ pDevExt->busNumber = uBusNumber; pDevExt->slotNumber = SlotNumber.u.AsULONG; #ifdef VBOX_WITH_GUEST_BUGCHECK_DETECTION rc = hlpRegisterBugCheckCallback(pDevExt); #endif /* Do the actual VBox init ... */ if (NT_SUCCESS(rc)) { rc = vgdrvNtInit(pDrvObj, pDeviceObject, pRegPath); if (NT_SUCCESS(rc)) { Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x (succcess)\n", rc)); return rc; } /* bail out */ } IoDeleteSymbolicLink(&DosName); } else Log(("vgdrvNt4CreateDevice: IoCreateSymbolicLink failed with rc = %#x\n", rc)); IoDeleteDevice(pDeviceObject); } else Log(("vgdrvNt4CreateDevice: IoCreateDevice failed with rc = %#x\n", rc)); Log(("vgdrvNt4CreateDevice: Returning rc = 0x%x\n", rc)); return rc; }
/** * PnP Request handler. * * @param pDevObj Device object. * @param pIrp Request packet. */ NTSTATUS vgdrvNtPnP(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(("vgdrvNtPnP: 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(("vgdrvNtPnP: START_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vgdrvNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE); if ( NT_SUCCESS(rc) && NT_SUCCESS(pIrp->IoStatus.Status)) { Log(("vgdrvNtPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n", pStack->Parameters.StartDevice.AllocatedResources)); if (pStack->Parameters.StartDevice.AllocatedResources) rc = vgdrvNtInit(pDevObj, pIrp); else { Log(("vgdrvNtPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n", pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL)); rc = STATUS_UNSUCCESSFUL; } } if (NT_ERROR(rc)) { Log(("vgdrvNtPnP: START_DEVICE: Error: rc = 0x%x\n", rc)); /* Need to unmap memory in case of errors ... */ /** @todo r=bird: vgdrvNtInit maps it and is responsible for cleaning up its own friggin mess... * Fix it instead of kind of working around things there!! */ vgdrvNtUnmapVMMDevMemory(pDevExt); } break; } case IRP_MN_CANCEL_REMOVE_DEVICE: { Log(("vgdrvNtPnP: CANCEL_REMOVE_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vgdrvNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE); if (NT_SUCCESS(rc) && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGREMOVE) { /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */ pDevExt->enmDevState = pDevExt->enmPrevDevState; } /* Complete the IRP. */ break; } case IRP_MN_SURPRISE_REMOVAL: { Log(("vgdrvNtPnP: IRP_MN_SURPRISE_REMOVAL\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_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(("vgdrvNtPnP: QUERY_REMOVE_DEVICE\n")); #ifdef VBOX_REBOOT_ON_UNINSTALL Log(("vgdrvNtPnP: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n")); rc = STATUS_UNSUCCESSFUL; #endif if (NT_SUCCESS(rc)) { VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_PENDINGREMOVE); /* This IRP passed down to lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); Log(("vgdrvNtPnP: 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(("vgdrvNtPnP: REMOVE_DEVICE\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_REMOVED); /* Free hardware resources. */ /** @todo this should actually free I/O ports, interrupts, etc. * Update/bird: vgdrvNtCleanup actually does that... So, what's there to do? */ rc = vgdrvNtCleanup(pDevObj); Log(("vgdrvNtPnP: REMOVE_DEVICE: vgdrvNtCleanup 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(("vgdrvNtPnP: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc)); IoDetachDevice(pDevExt->pNextLowerDriver); Log(("vgdrvNtPnP: REMOVE_DEVICE: Removing device ...\n")); /* Destroy device extension and clean up everything else. */ VGDrvCommonDeleteDevExt(&pDevExt->Core); /* Remove DOS device + symbolic link. */ UNICODE_STRING win32Name; RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS); IoDeleteSymbolicLink(&win32Name); Log(("vgdrvNtPnP: REMOVE_DEVICE: Deleting device ...\n")); /* Last action: Delete our device! pDevObj is *not* failed * anymore after this call! */ IoDeleteDevice(pDevObj); Log(("vgdrvNtPnP: 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(("vgdrvNtPnP: CANCEL_STOP_DEVICE\n")); /* This must be handled first by the lower driver. */ rc = vgdrvNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE); if (NT_SUCCESS(rc) && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGSTOP) { /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */ pDevExt->enmDevState = pDevExt->enmPrevDevState; } /* Complete the IRP. */ break; } case IRP_MN_QUERY_STOP_DEVICE: { Log(("vgdrvNtPnP: QUERY_STOP_DEVICE\n")); #ifdef VBOX_REBOOT_ON_UNINSTALL Log(("vgdrvNtPnP: 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, VGDRVNTDEVSTATE_PENDINGSTOP); /* This IRP passed down to lower driver. */ pIrp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(pIrp); rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp); Log(("vgdrvNtPnP: 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(("vgdrvNtPnP: STOP_DEVICE\n")); VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_STOPPED); /* Free hardware resources. */ /** @todo this should actually free I/O ports, interrupts, etc. * Update/bird: vgdrvNtCleanup actually does that... So, what's there to do? */ rc = vgdrvNtCleanup(pDevObj); Log(("vgdrvNtPnP: 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(("vgdrvNtPnP: 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(("vgdrvNtPnP: Returning with rc = 0x%x\n", rc)); return rc; }