Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendevice.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/io/device.c 00005 * PURPOSE: Device Object Management, including Notifications and Queues. 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Filip Navara (navaraf@reactos.org) 00008 * Hervé Poussineau (hpoussin@reactos.org) 00009 */ 00010 00011 /* INCLUDES *******************************************************************/ 00012 00013 #include <ntoskrnl.h> 00014 #define NDEBUG 00015 #include <debug.h> 00016 00017 /* GLOBALS ********************************************************************/ 00018 00019 ULONG IopDeviceObjectNumber = 0; 00020 LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead; 00021 KSPIN_LOCK ShutdownListLock; 00022 extern LIST_ENTRY IopDiskFileSystemQueueHead; 00023 extern LIST_ENTRY IopCdRomFileSystemQueueHead; 00024 extern LIST_ENTRY IopTapeFileSystemQueueHead; 00025 extern ERESOURCE IopDatabaseResource; 00026 00027 /* PRIVATE FUNCTIONS **********************************************************/ 00028 00029 VOID 00030 NTAPI 00031 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver) 00032 { 00033 PDEVICE_OBJECT DeviceObject; 00034 PAGED_CODE(); 00035 00036 /* Set the driver as initialized */ 00037 Driver->Flags |= DRVO_INITIALIZED; 00038 DeviceObject = Driver->DeviceObject; 00039 while (DeviceObject) 00040 { 00041 /* Set every device as initialized too */ 00042 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 00043 DeviceObject = DeviceObject->NextDevice; 00044 } 00045 } 00046 00047 VOID 00048 NTAPI 00049 IopDeleteDevice(IN PVOID ObjectBody) 00050 { 00051 PDEVICE_OBJECT DeviceObject = ObjectBody; 00052 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 00053 PAGED_CODE(); 00054 00055 /* Cleanup and free the device node */ 00056 if (DeviceNode) 00057 IopFreeDeviceNode(DeviceNode); 00058 00059 /* Dereference the driver object, referenced in IoCreateDevice */ 00060 if (DeviceObject->DriverObject) 00061 ObDereferenceObject(DeviceObject->DriverObject); 00062 } 00063 00064 00065 PDEVICE_OBJECT 00066 NTAPI 00067 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, 00068 IN PDEVICE_OBJECT TargetDevice, 00069 OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL) 00070 { 00071 PDEVICE_OBJECT AttachedDevice; 00072 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension; 00073 00074 /* Get the Attached Device and source extension */ 00075 AttachedDevice = IoGetAttachedDevice(TargetDevice); 00076 SourceDeviceExtension = IoGetDevObjExtension(SourceDevice); 00077 ASSERT(SourceDeviceExtension->AttachedTo == NULL); 00078 00079 /* Make sure that it's in a correct state */ 00080 if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) || 00081 (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags & 00082 (DOE_UNLOAD_PENDING | 00083 DOE_DELETE_PENDING | 00084 DOE_REMOVE_PENDING | 00085 DOE_REMOVE_PROCESSED))) 00086 { 00087 /* Device was unloading or being removed */ 00088 AttachedDevice = NULL; 00089 } 00090 else 00091 { 00092 /* Update atached device fields */ 00093 AttachedDevice->AttachedDevice = SourceDevice; 00094 AttachedDevice->Spare1++; 00095 00096 /* Update the source with the attached data */ 00097 SourceDevice->StackSize = AttachedDevice->StackSize + 1; 00098 SourceDevice->AlignmentRequirement = AttachedDevice-> 00099 AlignmentRequirement; 00100 SourceDevice->SectorSize = AttachedDevice->SectorSize; 00101 00102 /* Check for pending start flag */ 00103 if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags & 00104 DOE_START_PENDING) 00105 { 00106 /* Propagate */ 00107 IoGetDevObjExtension(SourceDevice)->ExtensionFlags |= 00108 DOE_START_PENDING; 00109 } 00110 00111 /* Set the attachment in the device extension */ 00112 SourceDeviceExtension->AttachedTo = AttachedDevice; 00113 } 00114 00115 /* Return the attached device */ 00116 if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice; 00117 return AttachedDevice; 00118 } 00119 00120 VOID 00121 NTAPI 00122 IoShutdownPnpDevices(VOID) 00123 { 00124 /* This routine is only used by Driver Verifier to validate shutdown */ 00125 return; 00126 } 00127 00128 VOID 00129 NTAPI 00130 IoShutdownSystem(IN ULONG Phase) 00131 { 00132 PLIST_ENTRY ListEntry; 00133 PDEVICE_OBJECT DeviceObject; 00134 PSHUTDOWN_ENTRY ShutdownEntry; 00135 IO_STATUS_BLOCK StatusBlock; 00136 PIRP Irp; 00137 KEVENT Event; 00138 NTSTATUS Status; 00139 00140 /* Initialize an event to wait on */ 00141 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00142 00143 /* What phase? */ 00144 if (Phase == 0) 00145 { 00146 /* Shutdown PnP */ 00147 IoShutdownPnpDevices(); 00148 00149 /* Loop first-chance shutdown notifications */ 00150 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead, 00151 &ShutdownListLock); 00152 while (ListEntry) 00153 { 00154 /* Get the shutdown entry */ 00155 ShutdownEntry = CONTAINING_RECORD(ListEntry, 00156 SHUTDOWN_ENTRY, 00157 ShutdownList); 00158 00159 /* Get the attached device */ 00160 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject); 00161 00162 /* Build the shutdown IRP and call the driver */ 00163 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 00164 DeviceObject, 00165 NULL, 00166 0, 00167 NULL, 00168 &Event, 00169 &StatusBlock); 00170 Status = IoCallDriver(DeviceObject, Irp); 00171 if (Status == STATUS_PENDING) 00172 { 00173 /* Wait on the driver */ 00174 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00175 } 00176 00177 /* Remove the flag */ 00178 ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 00179 00180 /* Get rid of our reference to it */ 00181 ObDereferenceObject(ShutdownEntry->DeviceObject); 00182 00183 /* Free the shutdown entry and reset the event */ 00184 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 00185 KeClearEvent(&Event); 00186 00187 /* Go to the next entry */ 00188 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead, 00189 &ShutdownListLock); 00190 } 00191 } 00192 else if (Phase == 1) 00193 { 00194 /* Acquire resource forever */ 00195 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 00196 00197 /* Shutdown disk file systems */ 00198 IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead); 00199 00200 /* Shutdown cdrom file systems */ 00201 IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead); 00202 00203 /* Shutdown tape filesystems */ 00204 IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead); 00205 00206 /* Loop last-chance shutdown notifications */ 00207 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead, 00208 &ShutdownListLock); 00209 while (ListEntry) 00210 { 00211 /* Get the shutdown entry */ 00212 ShutdownEntry = CONTAINING_RECORD(ListEntry, 00213 SHUTDOWN_ENTRY, 00214 ShutdownList); 00215 00216 /* Get the attached device */ 00217 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject); 00218 00219 /* Build the shutdown IRP and call the driver */ 00220 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 00221 DeviceObject, 00222 NULL, 00223 0, 00224 NULL, 00225 &Event, 00226 &StatusBlock); 00227 Status = IoCallDriver(DeviceObject, Irp); 00228 if (Status == STATUS_PENDING) 00229 { 00230 /* Wait on the driver */ 00231 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00232 } 00233 00234 /* Remove the flag */ 00235 ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 00236 00237 /* Get rid of our reference to it */ 00238 ObDereferenceObject(ShutdownEntry->DeviceObject); 00239 00240 /* Free the shutdown entry and reset the event */ 00241 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 00242 KeClearEvent(&Event); 00243 00244 /* Go to the next entry */ 00245 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead, 00246 &ShutdownListLock); 00247 } 00248 00249 } 00250 } 00251 00252 NTSTATUS 00253 NTAPI 00254 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, 00255 IN ACCESS_MASK DesiredAccess, 00256 OUT PFILE_OBJECT *FileObject, 00257 OUT PDEVICE_OBJECT *DeviceObject, 00258 IN ULONG AttachFlag) 00259 { 00260 OBJECT_ATTRIBUTES ObjectAttributes; 00261 IO_STATUS_BLOCK StatusBlock; 00262 PFILE_OBJECT LocalFileObject; 00263 HANDLE FileHandle; 00264 NTSTATUS Status; 00265 00266 /* Open the Device */ 00267 InitializeObjectAttributes(&ObjectAttributes, 00268 ObjectName, 00269 OBJ_KERNEL_HANDLE, 00270 NULL, 00271 NULL); 00272 Status = ZwOpenFile(&FileHandle, 00273 DesiredAccess, 00274 &ObjectAttributes, 00275 &StatusBlock, 00276 0, 00277 FILE_NON_DIRECTORY_FILE | AttachFlag); 00278 if (!NT_SUCCESS(Status)) return Status; 00279 00280 /* Get File Object */ 00281 Status = ObReferenceObjectByHandle(FileHandle, 00282 0, 00283 IoFileObjectType, 00284 KernelMode, 00285 (PVOID*)&LocalFileObject, 00286 NULL); 00287 if (NT_SUCCESS(Status)) 00288 { 00289 /* Return the requested data */ 00290 *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject); 00291 *FileObject = LocalFileObject; 00292 } 00293 00294 /* Close the handle */ 00295 ZwClose(FileHandle); 00296 00297 return Status; 00298 } 00299 00300 PDEVICE_OBJECT 00301 NTAPI 00302 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject) 00303 { 00304 PDEVICE_OBJECT LowestDevice; 00305 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 00306 00307 /* Get the current device and its extension */ 00308 LowestDevice = DeviceObject; 00309 DeviceExtension = IoGetDevObjExtension(LowestDevice); 00310 00311 /* Keep looping as long as we're attached */ 00312 while (DeviceExtension->AttachedTo) 00313 { 00314 /* Get the lowest device and its extension */ 00315 LowestDevice = DeviceExtension->AttachedTo; 00316 DeviceExtension = IoGetDevObjExtension(LowestDevice); 00317 } 00318 00319 /* Return the lowest device */ 00320 return LowestDevice; 00321 } 00322 00323 VOID 00324 NTAPI 00325 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject, 00326 IN PDEVICE_OBJECT DeviceObject, 00327 IN IOP_DEVICE_LIST_OPERATION Type) 00328 { 00329 PDEVICE_OBJECT Previous; 00330 00331 /* Check the type of operation */ 00332 if (Type == IopRemove) 00333 { 00334 /* Get the current device and check if it's the current one */ 00335 Previous = DeviceObject->DriverObject->DeviceObject; 00336 if (Previous == DeviceObject) 00337 { 00338 /* It is, simply unlink this one directly */ 00339 DeviceObject->DriverObject->DeviceObject = 00340 DeviceObject->NextDevice; 00341 } 00342 else 00343 { 00344 /* It's not, so loop until we find the device */ 00345 while (Previous->NextDevice != DeviceObject) 00346 { 00347 /* Not this one, keep moving */ 00348 Previous = Previous->NextDevice; 00349 } 00350 00351 /* We found it, now unlink us */ 00352 Previous->NextDevice = DeviceObject->NextDevice; 00353 } 00354 } 00355 else 00356 { 00357 /* Link the device object and the driver object */ 00358 DeviceObject->NextDevice = DriverObject->DeviceObject; 00359 DriverObject->DeviceObject = DeviceObject; 00360 } 00361 } 00362 00363 VOID 00364 NTAPI 00365 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject) 00366 { 00367 PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject; 00368 PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject); 00369 00370 /* Check if deletion is pending */ 00371 if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING) 00372 { 00373 if (DeviceObject->AttachedDevice) 00374 { 00375 DPRINT("Device object is in the middle of a device stack\n"); 00376 return; 00377 } 00378 00379 if (DeviceObject->ReferenceCount) 00380 { 00381 DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount); 00382 return; 00383 } 00384 00385 /* Check if we have a Security Descriptor */ 00386 if (DeviceObject->SecurityDescriptor) 00387 { 00388 /* Free it */ 00389 ExFreePoolWithTag(DeviceObject->SecurityDescriptor, TAG_SD); 00390 } 00391 00392 /* Remove the device from the list */ 00393 IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove); 00394 00395 /* Dereference the keep-alive */ 00396 ObDereferenceObject(DeviceObject); 00397 } 00398 00399 /* We can't unload a non-PnP driver here */ 00400 if (DriverObject->Flags & DRVO_LEGACY_DRIVER) 00401 { 00402 DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 00403 return; 00404 } 00405 00406 /* Return if we've already called unload (maybe we're in it?) */ 00407 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return; 00408 00409 /* We can't unload unless there's an unload handler */ 00410 if (!DriverObject->DriverUnload) 00411 { 00412 DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 00413 return; 00414 } 00415 00416 /* Bail if there are still devices present */ 00417 if (DriverObject->DeviceObject) 00418 { 00419 DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 00420 return; 00421 } 00422 00423 DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName); 00424 00425 /* Set the unload invoked flag */ 00426 DriverObject->Flags |= DRVO_UNLOAD_INVOKED; 00427 00428 /* Unload it */ 00429 DriverObject->DriverUnload(DriverObject); 00430 00431 /* Make object temporary so it can be deleted */ 00432 ObMakeTemporaryObject(DriverObject); 00433 } 00434 00435 VOID 00436 NTAPI 00437 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject, 00438 IN BOOLEAN ForceUnload) 00439 { 00440 /* Sanity check */ 00441 ASSERT(DeviceObject->ReferenceCount); 00442 00443 /* Dereference the device */ 00444 InterlockedDecrement(&DeviceObject->ReferenceCount); 00445 00446 /* 00447 * Check if we can unload it and it's safe to unload (or if we're forcing 00448 * an unload, which is OK too). 00449 */ 00450 ASSERT(!ForceUnload); 00451 if (!(DeviceObject->ReferenceCount) && 00452 (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING)) 00453 { 00454 /* Unload it */ 00455 IopUnloadDevice(DeviceObject); 00456 } 00457 } 00458 00459 VOID 00460 NTAPI 00461 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject, 00462 IN BOOLEAN Cancelable, 00463 IN ULONG Key) 00464 { 00465 PKDEVICE_QUEUE_ENTRY Entry; 00466 PIRP Irp; 00467 KIRQL OldIrql; 00468 00469 /* Acquire the cancel lock if this is cancelable */ 00470 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql); 00471 00472 /* Clear the current IRP */ 00473 DeviceObject->CurrentIrp = NULL; 00474 00475 /* Remove an entry from the queue */ 00476 Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key); 00477 if (Entry) 00478 { 00479 /* Get the IRP and set it */ 00480 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 00481 DeviceObject->CurrentIrp = Irp; 00482 00483 /* Check if this is a cancelable packet */ 00484 if (Cancelable) 00485 { 00486 /* Check if the caller requested no cancellation */ 00487 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 00488 DOE_SIO_NO_CANCEL) 00489 { 00490 /* He did, so remove the cancel routine */ 00491 Irp->CancelRoutine = NULL; 00492 } 00493 00494 /* Release the cancel lock */ 00495 IoReleaseCancelSpinLock(OldIrql); 00496 } 00497 00498 /* Call the Start I/O Routine */ 00499 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 00500 } 00501 else 00502 { 00503 /* Otherwise, release the cancel lock if we had acquired it */ 00504 if (Cancelable) IoReleaseCancelSpinLock(OldIrql); 00505 } 00506 } 00507 00508 VOID 00509 NTAPI 00510 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject, 00511 IN BOOLEAN Cancelable) 00512 { 00513 PKDEVICE_QUEUE_ENTRY Entry; 00514 PIRP Irp; 00515 KIRQL OldIrql; 00516 00517 /* Acquire the cancel lock if this is cancelable */ 00518 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql); 00519 00520 /* Clear the current IRP */ 00521 DeviceObject->CurrentIrp = NULL; 00522 00523 /* Remove an entry from the queue */ 00524 Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue); 00525 if (Entry) 00526 { 00527 /* Get the IRP and set it */ 00528 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 00529 DeviceObject->CurrentIrp = Irp; 00530 00531 /* Check if this is a cancelable packet */ 00532 if (Cancelable) 00533 { 00534 /* Check if the caller requested no cancellation */ 00535 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 00536 DOE_SIO_NO_CANCEL) 00537 { 00538 /* He did, so remove the cancel routine */ 00539 Irp->CancelRoutine = NULL; 00540 } 00541 00542 /* Release the cancel lock */ 00543 IoReleaseCancelSpinLock(OldIrql); 00544 } 00545 00546 /* Call the Start I/O Routine */ 00547 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 00548 } 00549 else 00550 { 00551 /* Otherwise, release the cancel lock if we had acquired it */ 00552 if (Cancelable) IoReleaseCancelSpinLock(OldIrql); 00553 } 00554 } 00555 00556 VOID 00557 NTAPI 00558 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject, 00559 IN ULONG Key, 00560 IN ULONG Flags) 00561 { 00562 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 00563 ULONG CurrentKey = Key; 00564 ULONG CurrentFlags = Flags; 00565 00566 /* Get the device extension and start the packet loop */ 00567 DeviceExtension = IoGetDevObjExtension(DeviceObject); 00568 while (TRUE) 00569 { 00570 /* Increase the count */ 00571 if (InterlockedIncrement(&DeviceExtension->StartIoCount) > 1) 00572 { 00573 /* 00574 * We've already called the routine once... 00575 * All we have to do is save the key and add the new flags 00576 */ 00577 DeviceExtension->StartIoFlags |= CurrentFlags; 00578 DeviceExtension->StartIoKey = CurrentKey; 00579 } 00580 else 00581 { 00582 /* Mask out the current packet flags and key */ 00583 DeviceExtension->StartIoFlags &= ~(DOE_SIO_WITH_KEY | 00584 DOE_SIO_NO_KEY | 00585 DOE_SIO_CANCELABLE); 00586 DeviceExtension->StartIoKey = 0; 00587 00588 /* Check if this is a packet start with key */ 00589 if (Flags & DOE_SIO_WITH_KEY) 00590 { 00591 /* Start the packet with a key */ 00592 IopStartNextPacketByKey(DeviceObject, 00593 (Flags & DOE_SIO_CANCELABLE) ? 00594 TRUE : FALSE, 00595 CurrentKey); 00596 } 00597 else if (Flags & DOE_SIO_NO_KEY) 00598 { 00599 /* Start the packet */ 00600 IopStartNextPacket(DeviceObject, 00601 (Flags & DOE_SIO_CANCELABLE) ? 00602 TRUE : FALSE); 00603 } 00604 } 00605 00606 /* Decrease the Start I/O count and check if it's 0 now */ 00607 if (!InterlockedDecrement(&DeviceExtension->StartIoCount)) 00608 { 00609 /* Get the current active key and flags */ 00610 CurrentKey = DeviceExtension->StartIoKey; 00611 CurrentFlags = DeviceExtension->StartIoFlags & (DOE_SIO_WITH_KEY | 00612 DOE_SIO_NO_KEY | 00613 DOE_SIO_CANCELABLE); 00614 00615 /* Check if we should still loop */ 00616 if (!(CurrentFlags & (DOE_SIO_WITH_KEY | DOE_SIO_NO_KEY))) break; 00617 } 00618 else 00619 { 00620 /* There are still Start I/Os active, so quit this loop */ 00621 break; 00622 } 00623 } 00624 } 00625 00626 NTSTATUS 00627 NTAPI 00628 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, 00629 OUT PDEVICE_NODE *DeviceNode) 00630 { 00631 NTSTATUS Status; 00632 IO_STACK_LOCATION Stack = {0}; 00633 PDEVICE_RELATIONS DeviceRelations; 00634 PDEVICE_OBJECT DeviceObject = NULL; 00635 00636 ASSERT(FileObject); 00637 00638 /* Get DeviceObject related to given FileObject */ 00639 DeviceObject = IoGetRelatedDeviceObject(FileObject); 00640 if (!DeviceObject) return STATUS_NO_SUCH_DEVICE; 00641 00642 /* Define input parameters */ 00643 Stack.MajorFunction = IRP_MJ_PNP; 00644 Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; 00645 Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; 00646 Stack.FileObject = FileObject; 00647 00648 /* Call the driver to query all relations (IRP_MJ_PNP) */ 00649 Status = IopSynchronousCall(DeviceObject, 00650 &Stack, 00651 (PVOID)&DeviceRelations); 00652 if (!NT_SUCCESS(Status)) return Status; 00653 00654 /* Make sure it's not NULL and contains only one object */ 00655 ASSERT(DeviceRelations); 00656 ASSERT(DeviceRelations->Count == 1); 00657 00658 /* Finally get the device node */ 00659 *DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]); 00660 if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE; 00661 00662 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */ 00663 ExFreePool(DeviceRelations); 00664 00665 return Status; 00666 } 00667 00668 /* PUBLIC FUNCTIONS ***********************************************************/ 00669 00670 /* 00671 * IoAttachDevice 00672 * 00673 * Layers a device over the highest device in a device stack. 00674 * 00675 * Parameters 00676 * SourceDevice 00677 * Device to be attached. 00678 * 00679 * TargetDevice 00680 * Name of the target device. 00681 * 00682 * AttachedDevice 00683 * Caller storage for the device attached to. 00684 * 00685 * Status 00686 * @implemented 00687 */ 00688 NTSTATUS 00689 NTAPI 00690 IoAttachDevice(PDEVICE_OBJECT SourceDevice, 00691 PUNICODE_STRING TargetDeviceName, 00692 PDEVICE_OBJECT *AttachedDevice) 00693 { 00694 NTSTATUS Status; 00695 PFILE_OBJECT FileObject = NULL; 00696 PDEVICE_OBJECT TargetDevice = NULL; 00697 00698 /* Call the helper routine for an attach operation */ 00699 Status = IopGetDeviceObjectPointer(TargetDeviceName, 00700 FILE_READ_ATTRIBUTES, 00701 &FileObject, 00702 &TargetDevice, 00703 IO_ATTACH_DEVICE_API); 00704 if (!NT_SUCCESS(Status)) return Status; 00705 00706 /* Attach the device */ 00707 Status = IoAttachDeviceToDeviceStackSafe(SourceDevice, 00708 TargetDevice, 00709 AttachedDevice); 00710 00711 /* Dereference it */ 00712 ObDereferenceObject(FileObject); 00713 return Status; 00714 } 00715 00716 /* 00717 * IoAttachDeviceByPointer 00718 * 00719 * Status 00720 * @implemented 00721 */ 00722 NTSTATUS 00723 NTAPI 00724 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice, 00725 IN PDEVICE_OBJECT TargetDevice) 00726 { 00727 PDEVICE_OBJECT AttachedDevice; 00728 NTSTATUS Status = STATUS_SUCCESS; 00729 00730 /* Do the Attach */ 00731 AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice); 00732 if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE; 00733 00734 /* Return the status */ 00735 return Status; 00736 } 00737 00738 /* 00739 * @implemented 00740 */ 00741 PDEVICE_OBJECT 00742 NTAPI 00743 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice, 00744 IN PDEVICE_OBJECT TargetDevice) 00745 { 00746 /* Attach it safely */ 00747 return IopAttachDeviceToDeviceStackSafe(SourceDevice, 00748 TargetDevice, 00749 NULL); 00750 } 00751 00752 /* 00753 * @implemented 00754 */ 00755 NTSTATUS 00756 NTAPI 00757 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, 00758 IN PDEVICE_OBJECT TargetDevice, 00759 IN OUT PDEVICE_OBJECT *AttachedToDeviceObject) 00760 { 00761 /* Call the internal function */ 00762 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice, 00763 TargetDevice, 00764 AttachedToDeviceObject)) 00765 { 00766 /* Nothing found */ 00767 return STATUS_NO_SUCH_DEVICE; 00768 } 00769 00770 /* Success! */ 00771 return STATUS_SUCCESS; 00772 } 00773 00774 /* 00775 * IoCreateDevice 00776 * 00777 * Allocates memory for and intializes a device object for use for 00778 * a driver. 00779 * 00780 * Parameters 00781 * DriverObject 00782 * Driver object passed by IO Manager when the driver was loaded. 00783 * 00784 * DeviceExtensionSize 00785 * Number of bytes for the device extension. 00786 * 00787 * DeviceName 00788 * Unicode name of device. 00789 * 00790 * DeviceType 00791 * Device type of the new device. 00792 * 00793 * DeviceCharacteristics 00794 * Bit mask of device characteristics. 00795 * 00796 * Exclusive 00797 * TRUE if only one thread can access the device at a time. 00798 * 00799 * DeviceObject 00800 * On successful return this parameter is filled by pointer to 00801 * allocated device object. 00802 * 00803 * Status 00804 * @implemented 00805 */ 00806 NTSTATUS 00807 NTAPI 00808 IoCreateDevice(IN PDRIVER_OBJECT DriverObject, 00809 IN ULONG DeviceExtensionSize, 00810 IN PUNICODE_STRING DeviceName, 00811 IN DEVICE_TYPE DeviceType, 00812 IN ULONG DeviceCharacteristics, 00813 IN BOOLEAN Exclusive, 00814 OUT PDEVICE_OBJECT *DeviceObject) 00815 { 00816 WCHAR AutoNameBuffer[20]; 00817 UNICODE_STRING AutoName; 00818 PDEVICE_OBJECT CreatedDeviceObject; 00819 PDEVOBJ_EXTENSION DeviceObjectExtension; 00820 OBJECT_ATTRIBUTES ObjectAttributes; 00821 NTSTATUS Status; 00822 ULONG AlignedDeviceExtensionSize; 00823 ULONG TotalSize; 00824 HANDLE TempHandle; 00825 PAGED_CODE(); 00826 00827 /* Check if we have to generate a name */ 00828 if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME) 00829 { 00830 /* Generate it */ 00831 swprintf(AutoNameBuffer, 00832 L"\\Device\\%08lx", 00833 InterlockedIncrementUL(&IopDeviceObjectNumber)); 00834 00835 /* Initialize the name */ 00836 RtlInitUnicodeString(&AutoName, AutoNameBuffer); 00837 DeviceName = &AutoName; 00838 } 00839 00840 /* Initialize the Object Attributes */ 00841 InitializeObjectAttributes(&ObjectAttributes, 00842 DeviceName, 00843 OBJ_KERNEL_HANDLE, 00844 NULL, 00845 NULL); 00846 00847 /* Honor exclusive flag */ 00848 if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE; 00849 00850 /* Create a permanent object for named devices */ 00851 if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT; 00852 00853 /* Align the Extension Size to 8-bytes */ 00854 AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7; 00855 00856 /* Total Size */ 00857 TotalSize = AlignedDeviceExtensionSize + 00858 sizeof(DEVICE_OBJECT) + 00859 sizeof(EXTENDED_DEVOBJ_EXTENSION); 00860 00861 /* Create the Device Object */ 00862 *DeviceObject = NULL; 00863 Status = ObCreateObject(KernelMode, 00864 IoDeviceObjectType, 00865 &ObjectAttributes, 00866 KernelMode, 00867 NULL, 00868 TotalSize, 00869 0, 00870 0, 00871 (PVOID*)&CreatedDeviceObject); 00872 if (!NT_SUCCESS(Status)) return Status; 00873 00874 /* Clear the whole Object and extension so we don't null stuff manually */ 00875 RtlZeroMemory(CreatedDeviceObject, TotalSize); 00876 00877 /* 00878 * Setup the Type and Size. Note that we don't use the aligned size, 00879 * because that's only padding for the DevObjExt and not part of the Object. 00880 */ 00881 CreatedDeviceObject->Type = IO_TYPE_DEVICE; 00882 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize; 00883 00884 /* The kernel extension is after the driver internal extension */ 00885 DeviceObjectExtension = (PDEVOBJ_EXTENSION) 00886 ((ULONG_PTR)(CreatedDeviceObject + 1) + 00887 AlignedDeviceExtensionSize); 00888 00889 /* Set the Type and Size. Question: why is Size 0 on Windows? */ 00890 DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION; 00891 DeviceObjectExtension->Size = 0; 00892 00893 /* Initialize with Power Manager */ 00894 PoInitializeDeviceObject(DeviceObjectExtension); 00895 00896 /* Link the Object and Extension */ 00897 DeviceObjectExtension->DeviceObject = CreatedDeviceObject; 00898 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension; 00899 00900 /* Set Device Object Data */ 00901 CreatedDeviceObject->DeviceType = DeviceType; 00902 CreatedDeviceObject->Characteristics = DeviceCharacteristics; 00903 CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ? 00904 CreatedDeviceObject + 1 : 00905 NULL; 00906 CreatedDeviceObject->StackSize = 1; 00907 CreatedDeviceObject->AlignmentRequirement = 0; 00908 00909 /* Set the Flags */ 00910 CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING; 00911 if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE; 00912 if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME; 00913 00914 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */ 00915 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) || 00916 (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) || 00917 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) || 00918 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)) 00919 { 00920 /* Create Vpb */ 00921 Status = IopCreateVpb(CreatedDeviceObject); 00922 if (!NT_SUCCESS(Status)) 00923 { 00924 /* Dereference the device object and fail */ 00925 ObDereferenceObject(CreatedDeviceObject); 00926 return Status; 00927 } 00928 00929 /* Initialize Lock Event */ 00930 KeInitializeEvent(&CreatedDeviceObject->DeviceLock, 00931 SynchronizationEvent, 00932 TRUE); 00933 } 00934 00935 /* Set the right Sector Size */ 00936 switch (DeviceType) 00937 { 00938 /* All disk systems */ 00939 case FILE_DEVICE_DISK_FILE_SYSTEM: 00940 case FILE_DEVICE_DISK: 00941 case FILE_DEVICE_VIRTUAL_DISK: 00942 00943 /* The default is 512 bytes */ 00944 CreatedDeviceObject->SectorSize = 512; 00945 break; 00946 00947 /* CD-ROM file systems */ 00948 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 00949 00950 /* The default is 2048 bytes */ 00951 CreatedDeviceObject->SectorSize = 2048; 00952 } 00953 00954 /* Create the Device Queue */ 00955 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) || 00956 (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) || 00957 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) || 00958 (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) || 00959 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM)) 00960 { 00961 /* Simple FS Devices, they don't need a real Device Queue */ 00962 InitializeListHead(&CreatedDeviceObject->Queue.ListEntry); 00963 } 00964 else 00965 { 00966 /* An actual Device, initialize its DQ */ 00967 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue); 00968 } 00969 00970 /* Insert the Object */ 00971 Status = ObInsertObject(CreatedDeviceObject, 00972 NULL, 00973 FILE_READ_DATA | FILE_WRITE_DATA, 00974 1, 00975 (PVOID*)&CreatedDeviceObject, 00976 &TempHandle); 00977 if (!NT_SUCCESS(Status)) return Status; 00978 00979 /* Now do the final linking */ 00980 ObReferenceObject(DriverObject); 00981 ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0); 00982 CreatedDeviceObject->DriverObject = DriverObject; 00983 IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd); 00984 00985 /* Link with the power manager */ 00986 if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject); 00987 00988 /* Close the temporary handle and return to caller */ 00989 ObCloseHandle(TempHandle, KernelMode); 00990 *DeviceObject = CreatedDeviceObject; 00991 return STATUS_SUCCESS; 00992 } 00993 00994 /* 00995 * IoDeleteDevice 00996 * 00997 * Status 00998 * @implemented 00999 */ 01000 VOID 01001 NTAPI 01002 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject) 01003 { 01004 PIO_TIMER Timer; 01005 01006 /* Check if the device is registered for shutdown notifications */ 01007 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED) 01008 { 01009 /* Call the shutdown notifications */ 01010 IoUnregisterShutdownNotification(DeviceObject); 01011 } 01012 01013 /* Check if it has a timer */ 01014 Timer = DeviceObject->Timer; 01015 if (Timer) 01016 { 01017 /* Remove it and free it */ 01018 IopRemoveTimerFromTimerList(Timer); 01019 ExFreePoolWithTag(Timer, TAG_IO_TIMER); 01020 } 01021 01022 /* Check if the device has a name */ 01023 if (DeviceObject->Flags & DO_DEVICE_HAS_NAME) 01024 { 01025 /* It does, make it temporary so we can remove it */ 01026 ObMakeTemporaryObject(DeviceObject); 01027 } 01028 01029 /* Set the pending delete flag */ 01030 IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING; 01031 01032 /* Check if the device object can be unloaded */ 01033 if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject); 01034 } 01035 01036 /* 01037 * IoDetachDevice 01038 * 01039 * Status 01040 * @implemented 01041 */ 01042 VOID 01043 NTAPI 01044 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice) 01045 { 01046 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 01047 01048 /* Sanity check */ 01049 DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice); 01050 ASSERT(DeviceExtension->AttachedTo == TargetDevice); 01051 01052 /* Remove the attachment */ 01053 DeviceExtension->AttachedTo = NULL; 01054 TargetDevice->AttachedDevice = NULL; 01055 01056 /* Check if it's ok to delete this device */ 01057 if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) && 01058 !(TargetDevice->ReferenceCount)) 01059 { 01060 /* It is, do it */ 01061 IopUnloadDevice(TargetDevice); 01062 } 01063 } 01064 01065 /* 01066 * @implemented 01067 */ 01068 NTSTATUS 01069 NTAPI 01070 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject, 01071 IN PDEVICE_OBJECT *DeviceObjectList, 01072 IN ULONG DeviceObjectListSize, 01073 OUT PULONG ActualNumberDeviceObjects) 01074 { 01075 ULONG ActualDevices = 1; 01076 PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject; 01077 01078 /* Find out how many devices we'll enumerate */ 01079 while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++; 01080 01081 /* Go back to the first */ 01082 CurrentDevice = DriverObject->DeviceObject; 01083 01084 /* Start by at least returning this */ 01085 *ActualNumberDeviceObjects = ActualDevices; 01086 01087 /* Check if we can support so many */ 01088 if ((ActualDevices * 4) > DeviceObjectListSize) 01089 { 01090 /* Fail because the buffer was too small */ 01091 return STATUS_BUFFER_TOO_SMALL; 01092 } 01093 01094 /* Check if the caller only wanted the size */ 01095 if (DeviceObjectList) 01096 { 01097 /* Loop through all the devices */ 01098 while (ActualDevices) 01099 { 01100 /* Reference each Device */ 01101 ObReferenceObject(CurrentDevice); 01102 01103 /* Add it to the list */ 01104 *DeviceObjectList = CurrentDevice; 01105 01106 /* Go to the next one */ 01107 CurrentDevice = CurrentDevice->NextDevice; 01108 ActualDevices--; 01109 DeviceObjectList++; 01110 } 01111 } 01112 01113 /* Return the status */ 01114 return STATUS_SUCCESS; 01115 } 01116 01117 /* 01118 * IoGetAttachedDevice 01119 * 01120 * Status 01121 * @implemented 01122 */ 01123 PDEVICE_OBJECT 01124 NTAPI 01125 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject) 01126 { 01127 /* Get the last attached device */ 01128 while (DeviceObject->AttachedDevice) 01129 { 01130 /* Move to the next one */ 01131 DeviceObject = DeviceObject->AttachedDevice; 01132 } 01133 01134 /* Return it */ 01135 return DeviceObject; 01136 } 01137 01138 /* 01139 * IoGetAttachedDeviceReference 01140 * 01141 * Status 01142 * @implemented 01143 */ 01144 PDEVICE_OBJECT 01145 NTAPI 01146 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject) 01147 { 01148 /* Reference the Attached Device */ 01149 DeviceObject = IoGetAttachedDevice(DeviceObject); 01150 ObReferenceObject(DeviceObject); 01151 return DeviceObject; 01152 } 01153 01154 /* 01155 * @implemented 01156 */ 01157 PDEVICE_OBJECT 01158 NTAPI 01159 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject) 01160 { 01161 /* Reference the lowest attached device */ 01162 DeviceObject = IopGetLowestDevice(DeviceObject); 01163 ObReferenceObject(DeviceObject); 01164 return DeviceObject; 01165 } 01166 01167 /* 01168 * IoGetDeviceObjectPointer 01169 * 01170 * Status 01171 * @implemented 01172 */ 01173 NTSTATUS 01174 NTAPI 01175 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, 01176 IN ACCESS_MASK DesiredAccess, 01177 OUT PFILE_OBJECT *FileObject, 01178 OUT PDEVICE_OBJECT *DeviceObject) 01179 { 01180 /* Call the helper routine for a normal operation */ 01181 return IopGetDeviceObjectPointer(ObjectName, 01182 DesiredAccess, 01183 FileObject, 01184 DeviceObject, 01185 0); 01186 } 01187 01188 /* 01189 * @implemented 01190 */ 01191 NTSTATUS 01192 NTAPI 01193 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject, 01194 OUT PDEVICE_OBJECT *DiskDeviceObject) 01195 { 01196 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 01197 PVPB Vpb; 01198 KIRQL OldIrql; 01199 NTSTATUS Status; 01200 01201 /* Make sure there's a VPB */ 01202 if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER; 01203 01204 /* Acquire it */ 01205 IoAcquireVpbSpinLock(&OldIrql); 01206 01207 /* Get the Device Extension */ 01208 DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject); 01209 01210 /* Make sure this one has a VPB too */ 01211 Vpb = DeviceExtension->Vpb; 01212 if (Vpb) 01213 { 01214 /* Make sure that it's mounted */ 01215 if ((Vpb->ReferenceCount) && 01216 (Vpb->Flags & VPB_MOUNTED)) 01217 { 01218 /* Return the Disk Device Object */ 01219 *DiskDeviceObject = Vpb->RealDevice; 01220 01221 /* Reference it and return success */ 01222 ObReferenceObject(Vpb->RealDevice); 01223 Status = STATUS_SUCCESS; 01224 } 01225 else 01226 { 01227 /* It's not, so return failure */ 01228 Status = STATUS_VOLUME_DISMOUNTED; 01229 } 01230 } 01231 else 01232 { 01233 /* Fail */ 01234 Status = STATUS_INVALID_PARAMETER; 01235 } 01236 01237 /* Release the lock */ 01238 IoReleaseVpbSpinLock(OldIrql); 01239 return Status; 01240 } 01241 01242 /* 01243 * @implemented 01244 */ 01245 PDEVICE_OBJECT 01246 NTAPI 01247 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject) 01248 { 01249 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 01250 PDEVICE_OBJECT LowerDeviceObject = NULL; 01251 01252 /* Make sure it's not getting deleted */ 01253 DeviceExtension = IoGetDevObjExtension(DeviceObject); 01254 if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING | 01255 DOE_DELETE_PENDING | 01256 DOE_REMOVE_PENDING | 01257 DOE_REMOVE_PROCESSED))) 01258 { 01259 /* Get the Lower Device Object */ 01260 LowerDeviceObject = DeviceExtension->AttachedTo; 01261 01262 /* Check that we got a valid device object */ 01263 if (LowerDeviceObject) 01264 { 01265 /* We did so let's reference it */ 01266 ObReferenceObject(LowerDeviceObject); 01267 } 01268 } 01269 01270 /* Return it */ 01271 return LowerDeviceObject; 01272 } 01273 01274 /* 01275 * @implemented 01276 */ 01277 PDEVICE_OBJECT 01278 NTAPI 01279 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject) 01280 { 01281 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject; 01282 01283 /* Check if we have a VPB with a device object */ 01284 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 01285 { 01286 /* Then use the DO from the VPB */ 01287 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 01288 DeviceObject = FileObject->Vpb->DeviceObject; 01289 } 01290 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 01291 (FileObject->DeviceObject->Vpb) && 01292 (FileObject->DeviceObject->Vpb->DeviceObject)) 01293 { 01294 /* The disk device actually has a VPB, so get the DO from there */ 01295 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 01296 } 01297 else 01298 { 01299 /* Otherwise, this was a direct open */ 01300 DeviceObject = FileObject->DeviceObject; 01301 } 01302 01303 /* Sanity check */ 01304 ASSERT(DeviceObject != NULL); 01305 01306 /* Check if we were attached */ 01307 if (DeviceObject->AttachedDevice) 01308 { 01309 /* Check if the file object has an extension present */ 01310 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) 01311 { 01312 /* Sanity check, direct open files can't have this */ 01313 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 01314 01315 /* Check if the extension is really present */ 01316 if (FileObject->FileObjectExtension) 01317 { 01318 /* FIXME: Unhandled yet */ 01319 DPRINT1("FOEs not supported\n"); 01320 ASSERT(FALSE); 01321 } 01322 } 01323 01324 /* Return the highest attached device */ 01325 DeviceObject = IoGetAttachedDevice(DeviceObject); 01326 } 01327 01328 /* Return the DO we found */ 01329 return DeviceObject; 01330 } 01331 01332 /* 01333 * @implemented 01334 */ 01335 NTSTATUS 01336 NTAPI 01337 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, 01338 OUT PDEVICE_OBJECT *DeviceObject) 01339 { 01340 NTSTATUS Status; 01341 PDEVICE_NODE DeviceNode = NULL; 01342 01343 /* Call the internal helper function */ 01344 Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode); 01345 if (NT_SUCCESS(Status) && DeviceNode) 01346 { 01347 *DeviceObject = DeviceNode->PhysicalDeviceObject; 01348 } 01349 return Status; 01350 } 01351 01352 /* 01353 * @implemented 01354 */ 01355 PDEVICE_OBJECT 01356 NTAPI 01357 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject) 01358 { 01359 PDEVICE_OBJECT DeviceObject; 01360 01361 /* 01362 * If the FILE_OBJECT's VPB is defined, 01363 * get the device from it. 01364 */ 01365 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 01366 { 01367 /* Use the VPB's Device Object's */ 01368 DeviceObject = FileObject->Vpb->DeviceObject; 01369 } 01370 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 01371 (FileObject->DeviceObject->Vpb) && 01372 (FileObject->DeviceObject->Vpb->DeviceObject)) 01373 { 01374 /* Use the VPB's File System Object */ 01375 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 01376 } 01377 else 01378 { 01379 /* Use the FO's Device Object */ 01380 DeviceObject = FileObject->DeviceObject; 01381 } 01382 01383 /* Return the device object we found */ 01384 ASSERT(DeviceObject != NULL); 01385 return DeviceObject; 01386 } 01387 01388 /* 01389 * @implemented 01390 */ 01391 NTSTATUS 01392 NTAPI 01393 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject) 01394 { 01395 PSHUTDOWN_ENTRY Entry; 01396 01397 /* Allocate the shutdown entry */ 01398 Entry = ExAllocatePoolWithTag(NonPagedPool, 01399 sizeof(SHUTDOWN_ENTRY), 01400 TAG_SHUTDOWN_ENTRY); 01401 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 01402 01403 /* Set the DO */ 01404 Entry->DeviceObject = DeviceObject; 01405 01406 /* Reference it so it doesn't go away */ 01407 ObReferenceObject(DeviceObject); 01408 01409 /* Insert it into the list */ 01410 ExInterlockedInsertHeadList(&LastChanceShutdownListHead, 01411 &Entry->ShutdownList, 01412 &ShutdownListLock); 01413 01414 /* Set the shutdown registered flag */ 01415 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 01416 return STATUS_SUCCESS; 01417 } 01418 01419 /* 01420 * @implemented 01421 */ 01422 NTSTATUS 01423 NTAPI 01424 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 01425 { 01426 PSHUTDOWN_ENTRY Entry; 01427 01428 /* Allocate the shutdown entry */ 01429 Entry = ExAllocatePoolWithTag(NonPagedPool, 01430 sizeof(SHUTDOWN_ENTRY), 01431 TAG_SHUTDOWN_ENTRY); 01432 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 01433 01434 /* Set the DO */ 01435 Entry->DeviceObject = DeviceObject; 01436 01437 /* Reference it so it doesn't go away */ 01438 ObReferenceObject(DeviceObject); 01439 01440 /* Insert it into the list */ 01441 ExInterlockedInsertHeadList(&ShutdownListHead, 01442 &Entry->ShutdownList, 01443 &ShutdownListLock); 01444 01445 /* Set the shutdown registered flag */ 01446 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 01447 return STATUS_SUCCESS; 01448 } 01449 01450 /* 01451 * @implemented 01452 */ 01453 VOID 01454 NTAPI 01455 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 01456 { 01457 PSHUTDOWN_ENTRY ShutdownEntry; 01458 PLIST_ENTRY NextEntry; 01459 KIRQL OldIrql; 01460 01461 /* Remove the flag */ 01462 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 01463 01464 /* Acquire the shutdown lock and loop the shutdown list */ 01465 KeAcquireSpinLock(&ShutdownListLock, &OldIrql); 01466 NextEntry = ShutdownListHead.Flink; 01467 while (NextEntry != &ShutdownListHead) 01468 { 01469 /* Get the entry */ 01470 ShutdownEntry = CONTAINING_RECORD(NextEntry, 01471 SHUTDOWN_ENTRY, 01472 ShutdownList); 01473 01474 /* Get if the DO matches */ 01475 if (ShutdownEntry->DeviceObject == DeviceObject) 01476 { 01477 /* Remove it from the list */ 01478 RemoveEntryList(NextEntry); 01479 NextEntry = NextEntry->Blink; 01480 01481 /* Free the entry */ 01482 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 01483 01484 /* Get rid of our reference to it */ 01485 ObDereferenceObject(DeviceObject); 01486 } 01487 01488 /* Go to the next entry */ 01489 NextEntry = NextEntry->Flink; 01490 } 01491 01492 /* Now loop the last chance list */ 01493 NextEntry = LastChanceShutdownListHead.Flink; 01494 while (NextEntry != &LastChanceShutdownListHead) 01495 { 01496 /* Get the entry */ 01497 ShutdownEntry = CONTAINING_RECORD(NextEntry, 01498 SHUTDOWN_ENTRY, 01499 ShutdownList); 01500 01501 /* Get if the DO matches */ 01502 if (ShutdownEntry->DeviceObject == DeviceObject) 01503 { 01504 /* Remove it from the list */ 01505 RemoveEntryList(NextEntry); 01506 NextEntry = NextEntry->Blink; 01507 01508 /* Free the entry */ 01509 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 01510 01511 /* Get rid of our reference to it */ 01512 ObDereferenceObject(DeviceObject); 01513 } 01514 01515 /* Go to the next entry */ 01516 NextEntry = NextEntry->Flink; 01517 } 01518 01519 /* Release the shutdown lock */ 01520 KeReleaseSpinLock(&ShutdownListLock, OldIrql); 01521 } 01522 01523 /* 01524 * @implemented 01525 */ 01526 VOID 01527 NTAPI 01528 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject, 01529 IN BOOLEAN DeferredStartIo, 01530 IN BOOLEAN NonCancelable) 01531 { 01532 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 01533 01534 /* Get the Device Extension */ 01535 DeviceExtension = IoGetDevObjExtension(DeviceObject); 01536 01537 /* Set the flags the caller requested */ 01538 DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0; 01539 DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0; 01540 } 01541 01542 /* 01543 * @implemented 01544 */ 01545 VOID 01546 NTAPI 01547 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject, 01548 IN BOOLEAN Cancelable, 01549 IN ULONG Key) 01550 { 01551 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 01552 01553 /* Get the Device Extension */ 01554 DeviceExtension = IoGetDevObjExtension(DeviceObject); 01555 01556 /* Check if deferred start was requested */ 01557 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 01558 { 01559 /* Call our internal function to handle the defered case */ 01560 IopStartNextPacketByKeyEx(DeviceObject, 01561 Key, 01562 DOE_SIO_WITH_KEY | 01563 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 01564 } 01565 else 01566 { 01567 /* Call the normal routine */ 01568 IopStartNextPacketByKey(DeviceObject, Cancelable, Key); 01569 } 01570 } 01571 01572 /* 01573 * @implemented 01574 */ 01575 VOID 01576 NTAPI 01577 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject, 01578 IN BOOLEAN Cancelable) 01579 { 01580 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 01581 01582 /* Get the Device Extension */ 01583 DeviceExtension = IoGetDevObjExtension(DeviceObject); 01584 01585 /* Check if deferred start was requested */ 01586 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 01587 { 01588 /* Call our internal function to handle the defered case */ 01589 IopStartNextPacketByKeyEx(DeviceObject, 01590 0, 01591 DOE_SIO_NO_KEY | 01592 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 01593 } 01594 else 01595 { 01596 /* Call the normal routine */ 01597 IopStartNextPacket(DeviceObject, Cancelable); 01598 } 01599 } 01600 01601 /* 01602 * @implemented 01603 */ 01604 VOID 01605 NTAPI 01606 IoStartPacket(IN PDEVICE_OBJECT DeviceObject, 01607 IN PIRP Irp, 01608 IN PULONG Key, 01609 IN PDRIVER_CANCEL CancelFunction) 01610 { 01611 BOOLEAN Stat; 01612 KIRQL OldIrql, CancelIrql; 01613 01614 /* Raise to dispatch level */ 01615 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 01616 01617 /* Check if we should acquire the cancel lock */ 01618 if (CancelFunction) 01619 { 01620 /* Acquire and set it */ 01621 IoAcquireCancelSpinLock(&CancelIrql); 01622 Irp->CancelRoutine = CancelFunction; 01623 } 01624 01625 /* Check if we have a key */ 01626 if (Key) 01627 { 01628 /* Insert by key */ 01629 Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue, 01630 &Irp->Tail.Overlay.DeviceQueueEntry, 01631 *Key); 01632 } 01633 else 01634 { 01635 /* Insert without a key */ 01636 Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue, 01637 &Irp->Tail.Overlay.DeviceQueueEntry); 01638 } 01639 01640 /* Check if this was a first insert */ 01641 if (!Stat) 01642 { 01643 /* Set the IRP */ 01644 DeviceObject->CurrentIrp = Irp; 01645 01646 /* Check if this is a cancelable packet */ 01647 if (CancelFunction) 01648 { 01649 /* Check if the caller requested no cancellation */ 01650 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 01651 DOE_SIO_NO_CANCEL) 01652 { 01653 /* He did, so remove the cancel routine */ 01654 Irp->CancelRoutine = NULL; 01655 } 01656 01657 /* Release the cancel lock */ 01658 IoReleaseCancelSpinLock(CancelIrql); 01659 } 01660 01661 /* Call the Start I/O function */ 01662 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 01663 } 01664 else 01665 { 01666 /* The packet was inserted... check if we have a cancel function */ 01667 if (CancelFunction) 01668 { 01669 /* Check if the IRP got cancelled */ 01670 if (Irp->Cancel) 01671 { 01672 /* 01673 * Set the cancel IRQL, clear the currnet cancel routine and 01674 * call ours 01675 */ 01676 Irp->CancelIrql = CancelIrql; 01677 Irp->CancelRoutine = NULL; 01678 CancelFunction(DeviceObject, Irp); 01679 } 01680 else 01681 { 01682 /* Otherwise, release the lock */ 01683 IoReleaseCancelSpinLock(CancelIrql); 01684 } 01685 } 01686 } 01687 01688 /* Return back to previous IRQL */ 01689 KeLowerIrql(OldIrql); 01690 } 01691 01692 #if defined (_WIN64) 01693 ULONG 01694 NTAPI 01695 IoWMIDeviceObjectToProviderId( 01696 IN PDEVICE_OBJECT DeviceObject) 01697 { 01698 UNIMPLEMENTED; 01699 return 0; 01700 } 01701 #endif 01702 01703 /* EOF */ Generated on Sat May 26 2012 04:19:57 for ReactOS by
1.7.6.1
|