Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpnpreport.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * COPYRIGHT: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/io/pnpmgr/pnpreport.c 00005 * PURPOSE: Device Changes Reporting Functions 00006 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 00007 * Pierre Schweitzer 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* TYPES *******************************************************************/ 00017 00018 typedef struct _INTERNAL_WORK_QUEUE_ITEM 00019 { 00020 WORK_QUEUE_ITEM WorkItem; 00021 PDEVICE_OBJECT PhysicalDeviceObject; 00022 PDEVICE_CHANGE_COMPLETE_CALLBACK Callback; 00023 PVOID Context; 00024 PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure; 00025 } INTERNAL_WORK_QUEUE_ITEM, *PINTERNAL_WORK_QUEUE_ITEM; 00026 00027 NTSTATUS 00028 NTAPI 00029 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath, 00030 IN ULONG CreateOptions, 00031 OUT PHANDLE Handle); 00032 00033 NTSTATUS 00034 IopSetDeviceInstanceData(HANDLE InstanceKey, 00035 PDEVICE_NODE DeviceNode); 00036 00037 NTSTATUS 00038 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, 00039 PVOID Context); 00040 00041 NTSTATUS 00042 PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject, 00043 IN OUT PKEVENT SyncEvent OPTIONAL, 00044 IN OUT PNTSTATUS SyncStatus OPTIONAL, 00045 IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, 00046 IN PVOID Context OPTIONAL, 00047 IN PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure); 00048 00049 /* PRIVATE FUNCTIONS *********************************************************/ 00050 00051 PWCHAR 00052 IopGetInterfaceTypeString(INTERFACE_TYPE IfType) 00053 { 00054 switch (IfType) 00055 { 00056 case Internal: 00057 return L"Internal"; 00058 00059 case Isa: 00060 return L"Isa"; 00061 00062 case Eisa: 00063 return L"Eisa"; 00064 00065 case MicroChannel: 00066 return L"MicroChannel"; 00067 00068 case TurboChannel: 00069 return L"TurboChannel"; 00070 00071 case PCIBus: 00072 return L"PCIBus"; 00073 00074 case VMEBus: 00075 return L"VMEBus"; 00076 00077 case NuBus: 00078 return L"NuBus"; 00079 00080 case PCMCIABus: 00081 return L"PCMCIABus"; 00082 00083 case CBus: 00084 return L"CBus"; 00085 00086 case MPIBus: 00087 return L"MPIBus"; 00088 00089 case MPSABus: 00090 return L"MPSABus"; 00091 00092 case ProcessorInternal: 00093 return L"ProcessorInternal"; 00094 00095 case PNPISABus: 00096 return L"PNPISABus"; 00097 00098 case PNPBus: 00099 return L"PNPBus"; 00100 00101 case Vmcs: 00102 return L"Vmcs"; 00103 00104 default: 00105 DPRINT1("Invalid bus type: %d\n", IfType); 00106 return NULL; 00107 } 00108 } 00109 00110 VOID 00111 IopReportTargetDeviceChangeAsyncWorker(PVOID Context) 00112 { 00113 PINTERNAL_WORK_QUEUE_ITEM Item; 00114 00115 Item = (PINTERNAL_WORK_QUEUE_ITEM)Context; 00116 PpSetCustomTargetEvent(Item->PhysicalDeviceObject, NULL, NULL, Item->Callback, Item->Context, Item->NotificationStructure); 00117 ObDereferenceObject(Item->PhysicalDeviceObject); 00118 ExFreePoolWithTag(Context, ' pP'); 00119 } 00120 00121 NTSTATUS 00122 PpSetCustomTargetEvent(IN PDEVICE_OBJECT DeviceObject, 00123 IN OUT PKEVENT SyncEvent OPTIONAL, 00124 IN OUT PNTSTATUS SyncStatus OPTIONAL, 00125 IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, 00126 IN PVOID Context OPTIONAL, 00127 IN PTARGET_DEVICE_CUSTOM_NOTIFICATION NotificationStructure) 00128 { 00129 ASSERT(NotificationStructure != NULL); 00130 ASSERT(DeviceObject != NULL); 00131 00132 if (SyncEvent) 00133 { 00134 ASSERT(SyncStatus); 00135 *SyncStatus = STATUS_PENDING; 00136 } 00137 00138 /* That call is totally wrong but notifications handler must be fixed first */ 00139 IopNotifyPlugPlayNotification(DeviceObject, 00140 EventCategoryTargetDeviceChange, 00141 &GUID_PNP_CUSTOM_NOTIFICATION, 00142 NotificationStructure, 00143 NULL); 00144 00145 if (SyncEvent) 00146 { 00147 KeSetEvent(SyncEvent, IO_NO_INCREMENT, FALSE); 00148 *SyncStatus = STATUS_SUCCESS; 00149 } 00150 00151 return STATUS_SUCCESS; 00152 } 00153 00154 /* PUBLIC FUNCTIONS **********************************************************/ 00155 00156 /* 00157 * @implemented 00158 */ 00159 NTSTATUS 00160 NTAPI 00161 IoReportDetectedDevice(IN PDRIVER_OBJECT DriverObject, 00162 IN INTERFACE_TYPE LegacyBusType, 00163 IN ULONG BusNumber, 00164 IN ULONG SlotNumber, 00165 IN PCM_RESOURCE_LIST ResourceList, 00166 IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements OPTIONAL, 00167 IN BOOLEAN ResourceAssigned, 00168 IN OUT PDEVICE_OBJECT *DeviceObject OPTIONAL) 00169 { 00170 PDEVICE_NODE DeviceNode; 00171 PDEVICE_OBJECT Pdo; 00172 NTSTATUS Status; 00173 HANDLE InstanceKey; 00174 ULONG RequiredLength; 00175 UNICODE_STRING ValueName, ServiceName; 00176 WCHAR HardwareId[256]; 00177 PWCHAR IfString; 00178 ULONG IdLength; 00179 00180 DPRINT("IoReportDetectedDevice (DeviceObject %p, *DeviceObject %p)\n", 00181 DeviceObject, DeviceObject ? *DeviceObject : NULL); 00182 00183 /* Create the service name (eg. ACPI_HAL) */ 00184 ServiceName.Buffer = DriverObject->DriverName.Buffer + 00185 sizeof(DRIVER_ROOT_NAME) / sizeof(WCHAR) - 1; 00186 ServiceName.Length = DriverObject->DriverName.Length - 00187 sizeof(DRIVER_ROOT_NAME) + sizeof(WCHAR); 00188 ServiceName.MaximumLength = ServiceName.Length; 00189 00190 /* If the interface type is unknown, treat it as internal */ 00191 if (LegacyBusType == InterfaceTypeUndefined) 00192 LegacyBusType = Internal; 00193 00194 /* Get the string equivalent of the interface type */ 00195 IfString = IopGetInterfaceTypeString(LegacyBusType); 00196 00197 /* If NULL is returned then it's a bad type */ 00198 if (!IfString) 00199 return STATUS_INVALID_PARAMETER; 00200 00201 /* We use the caller's PDO if they supplied one */ 00202 if (DeviceObject && *DeviceObject) 00203 { 00204 Pdo = *DeviceObject; 00205 } 00206 else 00207 { 00208 /* Create the PDO */ 00209 Status = PnpRootCreateDevice(&ServiceName, 00210 NULL, 00211 &Pdo, 00212 NULL); 00213 if (!NT_SUCCESS(Status)) 00214 { 00215 DPRINT("PnpRootCreateDevice() failed (Status 0x%08lx)\n", Status); 00216 return Status; 00217 } 00218 } 00219 00220 /* Create the device node for the new PDO */ 00221 Status = IopCreateDeviceNode(IopRootDeviceNode, 00222 Pdo, 00223 NULL, 00224 &DeviceNode); 00225 00226 if (!NT_SUCCESS(Status)) 00227 { 00228 DPRINT("IopCreateDeviceNode() failed (Status 0x%08lx)\n", Status); 00229 return Status; 00230 } 00231 00232 /* We're enumerated already */ 00233 IopDeviceNodeSetFlag(DeviceNode, DNF_ENUMERATED); 00234 00235 /* We don't call AddDevice for devices reported this way */ 00236 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED); 00237 00238 /* We don't send IRP_MN_START_DEVICE */ 00239 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED); 00240 00241 /* We need to get device IDs */ 00242 #if 0 00243 IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_QUERY_IDS); 00244 #endif 00245 00246 /* This is a legacy driver for this device */ 00247 IopDeviceNodeSetFlag(DeviceNode, DNF_LEGACY_DRIVER); 00248 00249 /* Perform a manual configuration of our device */ 00250 IopActionInterrogateDeviceStack(DeviceNode, DeviceNode->Parent); 00251 IopActionConfigureChildServices(DeviceNode, DeviceNode->Parent); 00252 00253 /* Open a handle to the instance path key */ 00254 /* REG_OPTION_VOLATILE is a HACK!!! */ 00255 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, REG_OPTION_VOLATILE, &InstanceKey); 00256 if (!NT_SUCCESS(Status)) 00257 return Status; 00258 00259 /* Add DETECTEDInterfaceType\DriverName */ 00260 IdLength = 0; 00261 IdLength += swprintf(&HardwareId[IdLength], 00262 L"DETECTED%ls\\%wZ", 00263 IfString, 00264 &ServiceName); 00265 IdLength++; 00266 00267 /* Add DETECTED\DriverName */ 00268 IdLength += swprintf(&HardwareId[IdLength], 00269 L"DETECTED\\%wZ", 00270 &ServiceName); 00271 IdLength++; 00272 00273 /* Terminate the string with another null */ 00274 HardwareId[IdLength++] = UNICODE_NULL; 00275 00276 /* Store the value for CompatibleIDs */ 00277 RtlInitUnicodeString(&ValueName, L"CompatibleIDs"); 00278 Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR)); 00279 if (!NT_SUCCESS(Status)) 00280 { 00281 DPRINT("Failed to write the compatible IDs: 0x%x\n", Status); 00282 ZwClose(InstanceKey); 00283 return Status; 00284 } 00285 00286 /* Add a hardware ID if the driver didn't report one */ 00287 RtlInitUnicodeString(&ValueName, L"HardwareID"); 00288 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND) 00289 { 00290 /* Just use our most specific compatible ID */ 00291 IdLength = 0; 00292 IdLength += swprintf(&HardwareId[IdLength], 00293 L"DETECTED%ls\\%wZ", 00294 IfString, 00295 &ServiceName); 00296 IdLength++; 00297 00298 HardwareId[IdLength++] = UNICODE_NULL; 00299 00300 /* Write the value to the registry */ 00301 Status = ZwSetValueKey(InstanceKey, &ValueName, 0, REG_MULTI_SZ, HardwareId, IdLength * sizeof(WCHAR)); 00302 if (!NT_SUCCESS(Status)) 00303 { 00304 DPRINT("Failed to write the hardware ID: 0x%x\n", Status); 00305 ZwClose(InstanceKey); 00306 return Status; 00307 } 00308 } 00309 00310 /* Assign the resources to the device node */ 00311 DeviceNode->BootResources = ResourceList; 00312 DeviceNode->ResourceRequirements = ResourceRequirements; 00313 00314 /* Set appropriate flags */ 00315 if (DeviceNode->BootResources) 00316 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG); 00317 00318 if (!DeviceNode->ResourceRequirements && !DeviceNode->BootResources) 00319 IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED); 00320 00321 /* Write the resource information to the registry */ 00322 IopSetDeviceInstanceData(InstanceKey, DeviceNode); 00323 00324 /* If the caller didn't get the resources assigned for us, do it now */ 00325 if (!ResourceAssigned) 00326 { 00327 Status = IopAssignDeviceResources(DeviceNode); 00328 00329 /* See if we failed */ 00330 if (!NT_SUCCESS(Status)) 00331 { 00332 DPRINT("Assigning resources failed: 0x%x\n", Status); 00333 ZwClose(InstanceKey); 00334 return Status; 00335 } 00336 } 00337 00338 /* Close the instance key handle */ 00339 ZwClose(InstanceKey); 00340 00341 /* Register the given DO with PnP root if required */ 00342 if (DeviceObject && *DeviceObject) 00343 PnpRootRegisterDevice(*DeviceObject); 00344 00345 /* Report the device's enumeration to umpnpmgr */ 00346 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED, 00347 &DeviceNode->InstancePath); 00348 00349 /* Report the device's arrival to umpnpmgr */ 00350 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, 00351 &DeviceNode->InstancePath); 00352 00353 DPRINT1("Reported device: %S (%wZ)\n", HardwareId, &DeviceNode->InstancePath); 00354 00355 /* Return the PDO */ 00356 if (DeviceObject) *DeviceObject = Pdo; 00357 00358 return STATUS_SUCCESS; 00359 } 00360 00361 /* 00362 * @halfplemented 00363 */ 00364 NTSTATUS 00365 NTAPI 00366 IoReportResourceForDetection(IN PDRIVER_OBJECT DriverObject, 00367 IN PCM_RESOURCE_LIST DriverList OPTIONAL, 00368 IN ULONG DriverListSize OPTIONAL, 00369 IN PDEVICE_OBJECT DeviceObject OPTIONAL, 00370 IN PCM_RESOURCE_LIST DeviceList OPTIONAL, 00371 IN ULONG DeviceListSize OPTIONAL, 00372 OUT PBOOLEAN ConflictDetected) 00373 { 00374 PCM_RESOURCE_LIST ResourceList; 00375 NTSTATUS Status; 00376 00377 *ConflictDetected = FALSE; 00378 00379 if (!DriverList && !DeviceList) 00380 return STATUS_INVALID_PARAMETER; 00381 00382 /* Find the real list */ 00383 if (!DriverList) 00384 ResourceList = DeviceList; 00385 else 00386 ResourceList = DriverList; 00387 00388 /* Look for a resource conflict */ 00389 Status = IopDetectResourceConflict(ResourceList, FALSE, NULL); 00390 if (Status == STATUS_CONFLICTING_ADDRESSES) 00391 { 00392 /* Oh noes */ 00393 *ConflictDetected = TRUE; 00394 } 00395 else if (NT_SUCCESS(Status)) 00396 { 00397 /* Looks like we're good to go */ 00398 00399 /* TODO: Claim the resources in the ResourceMap */ 00400 } 00401 00402 return Status; 00403 } 00404 00405 VOID 00406 NTAPI 00407 IopSetEvent(IN PVOID Context) 00408 { 00409 PKEVENT Event = Context; 00410 00411 /* Set the event */ 00412 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 00413 } 00414 00415 /* 00416 * @implemented 00417 */ 00418 NTSTATUS 00419 NTAPI 00420 IoReportTargetDeviceChange(IN PDEVICE_OBJECT PhysicalDeviceObject, 00421 IN PVOID NotificationStructure) 00422 { 00423 KEVENT NotifyEvent; 00424 NTSTATUS Status, NotifyStatus; 00425 PTARGET_DEVICE_CUSTOM_NOTIFICATION notifyStruct = (PTARGET_DEVICE_CUSTOM_NOTIFICATION)NotificationStructure; 00426 00427 ASSERT(notifyStruct); 00428 00429 /* Check for valid PDO */ 00430 if (!IopIsValidPhysicalDeviceObject(PhysicalDeviceObject)) 00431 { 00432 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG)PhysicalDeviceObject, 0, 0); 00433 } 00434 00435 /* FileObject must be null. PnP will fill in it */ 00436 ASSERT(notifyStruct->FileObject == NULL); 00437 00438 /* Do not handle system PnP events */ 00439 if ((RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_QUERY_REMOVE), sizeof(GUID)) != sizeof(GUID)) || 00440 (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_CANCELLED), sizeof(GUID)) != sizeof(GUID)) || 00441 (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_COMPLETE), sizeof(GUID)) != sizeof(GUID))) 00442 { 00443 return STATUS_INVALID_DEVICE_REQUEST; 00444 } 00445 00446 if (notifyStruct->Version != 1) 00447 { 00448 return STATUS_INVALID_DEVICE_REQUEST; 00449 } 00450 00451 /* Initialize even that will let us know when PnP will have finished notify */ 00452 KeInitializeEvent(&NotifyEvent, NotificationEvent, FALSE); 00453 00454 Status = PpSetCustomTargetEvent(PhysicalDeviceObject, &NotifyEvent, &NotifyStatus, NULL, NULL, notifyStruct); 00455 /* If no error, wait for the notify to end and return the status of the notify and not of the event */ 00456 if (NT_SUCCESS(Status)) 00457 { 00458 KeWaitForSingleObject(&NotifyEvent, Executive, KernelMode, FALSE, NULL); 00459 Status = NotifyStatus; 00460 } 00461 00462 return Status; 00463 } 00464 00465 /* 00466 * @implemented 00467 */ 00468 NTSTATUS 00469 NTAPI 00470 IoReportTargetDeviceChangeAsynchronous(IN PDEVICE_OBJECT PhysicalDeviceObject, 00471 IN PVOID NotificationStructure, 00472 IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback OPTIONAL, 00473 IN PVOID Context OPTIONAL) 00474 { 00475 PINTERNAL_WORK_QUEUE_ITEM Item = NULL; 00476 PTARGET_DEVICE_CUSTOM_NOTIFICATION notifyStruct = (PTARGET_DEVICE_CUSTOM_NOTIFICATION)NotificationStructure; 00477 00478 ASSERT(notifyStruct); 00479 00480 /* Check for valid PDO */ 00481 if (!IopIsValidPhysicalDeviceObject(PhysicalDeviceObject)) 00482 { 00483 KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, 0x2, (ULONG)PhysicalDeviceObject, 0, 0); 00484 } 00485 00486 /* FileObject must be null. PnP will fill in it */ 00487 ASSERT(notifyStruct->FileObject == NULL); 00488 00489 /* Do not handle system PnP events */ 00490 if ((RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_QUERY_REMOVE), sizeof(GUID)) != sizeof(GUID)) || 00491 (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_CANCELLED), sizeof(GUID)) != sizeof(GUID)) || 00492 (RtlCompareMemory(&(notifyStruct->Event), &(GUID_TARGET_DEVICE_REMOVE_COMPLETE), sizeof(GUID)) != sizeof(GUID))) 00493 { 00494 return STATUS_INVALID_DEVICE_REQUEST; 00495 } 00496 00497 if (notifyStruct->Version != 1) 00498 { 00499 return STATUS_INVALID_DEVICE_REQUEST; 00500 } 00501 00502 /* We need to store all the data given by the caller with the WorkItem, so use our own struct */ 00503 Item = ExAllocatePoolWithTag(NonPagedPool, sizeof(INTERNAL_WORK_QUEUE_ITEM), ' pP'); 00504 if (!Item) return STATUS_INSUFFICIENT_RESOURCES; 00505 00506 /* Initialize all stuff */ 00507 ObReferenceObject(PhysicalDeviceObject); 00508 Item->NotificationStructure = notifyStruct; 00509 Item->PhysicalDeviceObject = PhysicalDeviceObject; 00510 Item->Callback = Callback; 00511 Item->Context = Context; 00512 ExInitializeWorkItem(&(Item->WorkItem), (PWORKER_THREAD_ROUTINE)IopReportTargetDeviceChangeAsyncWorker, Item); 00513 00514 /* Finally, queue the item, our work here is done */ 00515 ExQueueWorkItem(&(Item->WorkItem), DelayedWorkQueue); 00516 00517 return STATUS_PENDING; 00518 } Generated on Sun May 27 2012 04:37:18 for ReactOS by
1.7.6.1
|