ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pnpreport.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.