Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfdo.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS PCI bus driver 00003 * FILE: fdo.c 00004 * PURPOSE: PCI device object dispatch routines 00005 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 00006 * UPDATE HISTORY: 00007 * 10-09-2001 CSH Created 00008 */ 00009 00010 #include "pci.h" 00011 00012 #ifndef NDEBUG 00013 #define NDEBUG 00014 #endif 00015 #include <debug.h> 00016 00017 /*** PRIVATE *****************************************************************/ 00018 00019 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion; 00020 00021 static NTSTATUS NTAPI 00022 ForwardIrpAndWaitCompletion( 00023 IN PDEVICE_OBJECT DeviceObject, 00024 IN PIRP Irp, 00025 IN PVOID Context) 00026 { 00027 UNREFERENCED_PARAMETER(DeviceObject); 00028 if (Irp->PendingReturned) 00029 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); 00030 return STATUS_MORE_PROCESSING_REQUIRED; 00031 } 00032 00033 NTSTATUS NTAPI 00034 ForwardIrpAndWait( 00035 IN PDEVICE_OBJECT DeviceObject, 00036 IN PIRP Irp) 00037 { 00038 KEVENT Event; 00039 NTSTATUS Status; 00040 PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Ldo; 00041 ASSERT(LowerDevice); 00042 00043 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00044 IoCopyCurrentIrpStackLocationToNext(Irp); 00045 00046 IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE); 00047 00048 Status = IoCallDriver(LowerDevice, Irp); 00049 if (Status == STATUS_PENDING) 00050 { 00051 Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); 00052 if (NT_SUCCESS(Status)) 00053 Status = Irp->IoStatus.Status; 00054 } 00055 00056 return Status; 00057 } 00058 00059 static NTSTATUS 00060 FdoLocateChildDevice( 00061 PPCI_DEVICE *Device, 00062 PFDO_DEVICE_EXTENSION DeviceExtension, 00063 PCI_SLOT_NUMBER SlotNumber, 00064 PPCI_COMMON_CONFIG PciConfig) 00065 { 00066 PLIST_ENTRY CurrentEntry; 00067 PPCI_DEVICE CurrentDevice; 00068 00069 DPRINT("Called\n"); 00070 00071 CurrentEntry = DeviceExtension->DeviceListHead.Flink; 00072 while (CurrentEntry != &DeviceExtension->DeviceListHead) { 00073 CurrentDevice = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry); 00074 00075 /* If both vendor ID and device ID match, it is the same device */ 00076 if ((PciConfig->VendorID == CurrentDevice->PciConfig.VendorID) && 00077 (PciConfig->DeviceID == CurrentDevice->PciConfig.DeviceID) && 00078 (SlotNumber.u.AsULONG == CurrentDevice->SlotNumber.u.AsULONG)) { 00079 *Device = CurrentDevice; 00080 DPRINT("Done\n"); 00081 return STATUS_SUCCESS; 00082 } 00083 00084 CurrentEntry = CurrentEntry->Flink; 00085 } 00086 00087 *Device = NULL; 00088 DPRINT("Done\n"); 00089 return STATUS_UNSUCCESSFUL; 00090 } 00091 00092 00093 static NTSTATUS 00094 FdoEnumerateDevices( 00095 PDEVICE_OBJECT DeviceObject) 00096 { 00097 PFDO_DEVICE_EXTENSION DeviceExtension; 00098 PCI_COMMON_CONFIG PciConfig; 00099 PPCI_DEVICE Device; 00100 PCI_SLOT_NUMBER SlotNumber; 00101 ULONG DeviceNumber; 00102 ULONG FunctionNumber; 00103 ULONG Size; 00104 NTSTATUS Status; 00105 00106 DPRINT("Called\n"); 00107 00108 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00109 00110 DeviceExtension->DeviceListCount = 0; 00111 00112 /* Enumerate devices on the PCI bus */ 00113 SlotNumber.u.AsULONG = 0; 00114 for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++) 00115 { 00116 SlotNumber.u.bits.DeviceNumber = DeviceNumber; 00117 for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++) 00118 { 00119 SlotNumber.u.bits.FunctionNumber = FunctionNumber; 00120 00121 DPRINT("Bus %1lu Device %2lu Func %1lu\n", 00122 DeviceExtension->BusNumber, 00123 DeviceNumber, 00124 FunctionNumber); 00125 00126 RtlZeroMemory(&PciConfig, 00127 sizeof(PCI_COMMON_CONFIG)); 00128 00129 Size = HalGetBusData(PCIConfiguration, 00130 DeviceExtension->BusNumber, 00131 SlotNumber.u.AsULONG, 00132 &PciConfig, 00133 PCI_COMMON_HDR_LENGTH); 00134 DPRINT("Size %lu\n", Size); 00135 if (Size < PCI_COMMON_HDR_LENGTH) 00136 { 00137 if (FunctionNumber == 0) 00138 { 00139 break; 00140 } 00141 else 00142 { 00143 continue; 00144 } 00145 } 00146 00147 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n", 00148 DeviceExtension->BusNumber, 00149 DeviceNumber, 00150 FunctionNumber, 00151 PciConfig.VendorID, 00152 PciConfig.DeviceID); 00153 00154 Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber, &PciConfig); 00155 if (!NT_SUCCESS(Status)) 00156 { 00157 Device = (PPCI_DEVICE)ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_DEVICE),TAG_PCI); 00158 if (!Device) 00159 { 00160 /* FIXME: Cleanup resources for already discovered devices */ 00161 return STATUS_INSUFFICIENT_RESOURCES; 00162 } 00163 00164 RtlZeroMemory(Device, 00165 sizeof(PCI_DEVICE)); 00166 00167 Device->BusNumber = DeviceExtension->BusNumber; 00168 00169 RtlCopyMemory(&Device->SlotNumber, 00170 &SlotNumber, 00171 sizeof(PCI_SLOT_NUMBER)); 00172 00173 RtlCopyMemory(&Device->PciConfig, 00174 &PciConfig, 00175 sizeof(PCI_COMMON_CONFIG)); 00176 00177 ExInterlockedInsertTailList( 00178 &DeviceExtension->DeviceListHead, 00179 &Device->ListEntry, 00180 &DeviceExtension->DeviceListLock); 00181 } 00182 00183 DeviceExtension->DeviceListCount++; 00184 00185 /* Skip to next device if the current one is not a multifunction device */ 00186 if ((FunctionNumber == 0) && 00187 ((PciConfig.HeaderType & 0x80) == 0)) 00188 { 00189 break; 00190 } 00191 } 00192 } 00193 00194 DPRINT("Done\n"); 00195 00196 return STATUS_SUCCESS; 00197 } 00198 00199 00200 static NTSTATUS 00201 FdoQueryBusRelations( 00202 IN PDEVICE_OBJECT DeviceObject, 00203 IN PIRP Irp, 00204 PIO_STACK_LOCATION IrpSp) 00205 { 00206 PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL; 00207 PFDO_DEVICE_EXTENSION DeviceExtension; 00208 PDEVICE_RELATIONS Relations; 00209 PLIST_ENTRY CurrentEntry; 00210 PPCI_DEVICE Device; 00211 NTSTATUS Status; 00212 BOOLEAN ErrorOccurred; 00213 NTSTATUS ErrorStatus; 00214 ULONG Size; 00215 ULONG i; 00216 00217 UNREFERENCED_PARAMETER(IrpSp); 00218 00219 DPRINT("Called\n"); 00220 00221 ErrorStatus = STATUS_INSUFFICIENT_RESOURCES; 00222 00223 Status = STATUS_SUCCESS; 00224 00225 ErrorOccurred = FALSE; 00226 00227 FdoEnumerateDevices(DeviceObject); 00228 00229 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00230 00231 if (Irp->IoStatus.Information) { 00232 /* FIXME: Another bus driver has already created a DEVICE_RELATIONS 00233 structure so we must merge this structure with our own */ 00234 } 00235 00236 Size = sizeof(DEVICE_RELATIONS) + sizeof(Relations->Objects) * 00237 (DeviceExtension->DeviceListCount - 1); 00238 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size); 00239 if (!Relations) 00240 return STATUS_INSUFFICIENT_RESOURCES; 00241 00242 Relations->Count = DeviceExtension->DeviceListCount; 00243 00244 i = 0; 00245 CurrentEntry = DeviceExtension->DeviceListHead.Flink; 00246 while (CurrentEntry != &DeviceExtension->DeviceListHead) { 00247 Device = CONTAINING_RECORD(CurrentEntry, PCI_DEVICE, ListEntry); 00248 00249 PdoDeviceExtension = NULL; 00250 00251 if (!Device->Pdo) { 00252 /* Create a physical device object for the 00253 device as it does not already have one */ 00254 Status = IoCreateDevice( 00255 DeviceObject->DriverObject, 00256 sizeof(PDO_DEVICE_EXTENSION), 00257 NULL, 00258 FILE_DEVICE_CONTROLLER, 00259 FILE_AUTOGENERATED_DEVICE_NAME, 00260 FALSE, 00261 &Device->Pdo); 00262 if (!NT_SUCCESS(Status)) { 00263 DPRINT("IoCreateDevice() failed with status 0x%X\n", Status); 00264 ErrorStatus = Status; 00265 ErrorOccurred = TRUE; 00266 break; 00267 } 00268 00269 Device->Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 00270 00271 //Device->Pdo->Flags |= DO_POWER_PAGABLE; 00272 00273 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Device->Pdo->DeviceExtension; 00274 00275 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); 00276 00277 PdoDeviceExtension->Common.IsFDO = FALSE; 00278 00279 PdoDeviceExtension->Common.DeviceObject = Device->Pdo; 00280 00281 PdoDeviceExtension->Common.DevicePowerState = PowerDeviceD0; 00282 00283 PdoDeviceExtension->Fdo = DeviceObject; 00284 00285 PdoDeviceExtension->PciDevice = Device; 00286 00287 /* Add Device ID string */ 00288 Status = PciCreateDeviceIDString(&PdoDeviceExtension->DeviceID, Device); 00289 if (!NT_SUCCESS(Status)) 00290 { 00291 ErrorStatus = Status; 00292 ErrorOccurred = TRUE; 00293 break; 00294 } 00295 00296 DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceID.Buffer); 00297 00298 /* Add Instance ID string */ 00299 Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceID, Device); 00300 if (!NT_SUCCESS(Status)) 00301 { 00302 ErrorStatus = Status; 00303 ErrorOccurred = TRUE; 00304 break; 00305 } 00306 00307 /* Add Hardware IDs string */ 00308 Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIDs, Device); 00309 if (!NT_SUCCESS(Status)) 00310 { 00311 ErrorStatus = Status; 00312 ErrorOccurred = TRUE; 00313 break; 00314 } 00315 00316 /* Add Compatible IDs string */ 00317 Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIDs, Device); 00318 if (!NT_SUCCESS(Status)) 00319 { 00320 ErrorStatus = Status; 00321 ErrorOccurred = TRUE; 00322 break; 00323 } 00324 00325 /* Add device description string */ 00326 Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device); 00327 if (!NT_SUCCESS(Status)) 00328 { 00329 ErrorStatus = Status; 00330 ErrorOccurred = TRUE; 00331 break; 00332 } 00333 00334 /* Add device location string */ 00335 Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device); 00336 if (!NT_SUCCESS(Status)) 00337 { 00338 ErrorStatus = Status; 00339 ErrorOccurred = TRUE; 00340 break; 00341 } 00342 } 00343 00344 /* Reference the physical device object. The PnP manager 00345 will dereference it again when it is no longer needed */ 00346 ObReferenceObject(Device->Pdo); 00347 00348 Relations->Objects[i] = Device->Pdo; 00349 00350 i++; 00351 00352 CurrentEntry = CurrentEntry->Flink; 00353 } 00354 00355 if (ErrorOccurred) { 00356 /* FIXME: Cleanup all new PDOs created in this call. Please give me SEH!!! ;-) */ 00357 /* FIXME: Should IoAttachDeviceToDeviceStack() be undone? */ 00358 if (PdoDeviceExtension) { 00359 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceID); 00360 RtlFreeUnicodeString(&PdoDeviceExtension->InstanceID); 00361 RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIDs); 00362 RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIDs); 00363 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription); 00364 RtlFreeUnicodeString(&PdoDeviceExtension->DeviceLocation); 00365 } 00366 00367 ExFreePool(Relations); 00368 return ErrorStatus; 00369 } 00370 00371 Irp->IoStatus.Information = (ULONG_PTR)Relations; 00372 00373 DPRINT("Done\n"); 00374 00375 return Status; 00376 } 00377 00378 00379 static NTSTATUS 00380 FdoStartDevice( 00381 IN PDEVICE_OBJECT DeviceObject, 00382 IN PIRP Irp) 00383 { 00384 PFDO_DEVICE_EXTENSION DeviceExtension; 00385 PCM_RESOURCE_LIST AllocatedResources; 00386 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; 00387 ULONG FoundBusNumber = FALSE; 00388 ULONG i; 00389 00390 DPRINT("Called\n"); 00391 00392 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00393 00394 AllocatedResources = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources; 00395 if (!AllocatedResources) 00396 { 00397 DPRINT("No allocated resources sent to driver\n"); 00398 return STATUS_INSUFFICIENT_RESOURCES; 00399 } 00400 if (AllocatedResources->Count < 1) 00401 { 00402 DPRINT("Not enough allocated resources sent to driver\n"); 00403 return STATUS_INSUFFICIENT_RESOURCES; 00404 } 00405 if (AllocatedResources->List[0].PartialResourceList.Version != 1 00406 || AllocatedResources->List[0].PartialResourceList.Revision != 1) 00407 return STATUS_REVISION_MISMATCH; 00408 00409 ASSERT(DeviceExtension->State == dsStopped); 00410 00411 /* By default, use the bus number in the resource list header */ 00412 DeviceExtension->BusNumber = AllocatedResources->List[0].BusNumber; 00413 00414 for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++) 00415 { 00416 ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i]; 00417 switch (ResourceDescriptor->Type) 00418 { 00419 case CmResourceTypeBusNumber: 00420 { 00421 if (FoundBusNumber || ResourceDescriptor->u.BusNumber.Length != 1) 00422 return STATUS_INVALID_PARAMETER; 00423 /* Use this one instead */ 00424 ASSERT(AllocatedResources->List[0].BusNumber == ResourceDescriptor->u.BusNumber.Start); 00425 DeviceExtension->BusNumber = ResourceDescriptor->u.BusNumber.Start; 00426 DPRINT("Found bus number resource: %lu\n", DeviceExtension->BusNumber); 00427 FoundBusNumber = TRUE; 00428 break; 00429 } 00430 default: 00431 DPRINT("Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type); 00432 } 00433 } 00434 00435 InitializeListHead(&DeviceExtension->DeviceListHead); 00436 KeInitializeSpinLock(&DeviceExtension->DeviceListLock); 00437 DeviceExtension->DeviceListCount = 0; 00438 DeviceExtension->State = dsStarted; 00439 00440 ExInterlockedInsertTailList( 00441 &DriverExtension->BusListHead, 00442 &DeviceExtension->ListEntry, 00443 &DriverExtension->BusListLock); 00444 00445 Irp->IoStatus.Information = 0; 00446 00447 return STATUS_SUCCESS; 00448 } 00449 00450 00451 static NTSTATUS 00452 FdoSetPower( 00453 IN PDEVICE_OBJECT DeviceObject, 00454 IN PIRP Irp, 00455 PIO_STACK_LOCATION IrpSp) 00456 { 00457 NTSTATUS Status; 00458 00459 UNREFERENCED_PARAMETER(Irp); 00460 00461 DPRINT("Called\n"); 00462 00463 if (IrpSp->Parameters.Power.Type == DevicePowerState) { 00464 /* FIXME: Set device power state for the device */ 00465 Status = STATUS_UNSUCCESSFUL; 00466 } else { 00467 Status = STATUS_UNSUCCESSFUL; 00468 } 00469 00470 return Status; 00471 } 00472 00473 00474 /*** PUBLIC ******************************************************************/ 00475 00476 NTSTATUS 00477 FdoPnpControl( 00478 PDEVICE_OBJECT DeviceObject, 00479 PIRP Irp) 00480 /* 00481 * FUNCTION: Handle Plug and Play IRPs for the PCI device object 00482 * ARGUMENTS: 00483 * DeviceObject = Pointer to functional device object of the PCI driver 00484 * Irp = Pointer to IRP that should be handled 00485 * RETURNS: 00486 * Status 00487 */ 00488 { 00489 PFDO_DEVICE_EXTENSION DeviceExtension; 00490 PIO_STACK_LOCATION IrpSp; 00491 NTSTATUS Status = Irp->IoStatus.Status; 00492 00493 DPRINT("Called\n"); 00494 00495 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00496 00497 IrpSp = IoGetCurrentIrpStackLocation(Irp); 00498 switch (IrpSp->MinorFunction) { 00499 #if 0 00500 case IRP_MN_CANCEL_REMOVE_DEVICE: 00501 Status = STATUS_NOT_IMPLEMENTED; 00502 break; 00503 00504 case IRP_MN_CANCEL_STOP_DEVICE: 00505 Status = STATUS_NOT_IMPLEMENTED; 00506 break; 00507 00508 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 00509 Status = STATUS_NOT_IMPLEMENTED; 00510 break; 00511 00512 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 00513 Status = STATUS_NOT_IMPLEMENTED; 00514 break; 00515 #endif 00516 case IRP_MN_QUERY_DEVICE_RELATIONS: 00517 if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations) 00518 break; 00519 00520 Status = FdoQueryBusRelations(DeviceObject, Irp, IrpSp); 00521 Irp->IoStatus.Status = Status; 00522 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00523 return Status; 00524 #if 0 00525 case IRP_MN_QUERY_PNP_DEVICE_STATE: 00526 Status = STATUS_NOT_IMPLEMENTED; 00527 break; 00528 00529 case IRP_MN_QUERY_REMOVE_DEVICE: 00530 Status = STATUS_NOT_IMPLEMENTED; 00531 break; 00532 #endif 00533 case IRP_MN_START_DEVICE: 00534 DPRINT("IRP_MN_START_DEVICE received\n"); 00535 Status = ForwardIrpAndWait(DeviceObject, Irp); 00536 if (NT_SUCCESS(Status)) 00537 Status = FdoStartDevice(DeviceObject, Irp); 00538 00539 Irp->IoStatus.Status = Status; 00540 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00541 return Status; 00542 00543 case IRP_MN_QUERY_STOP_DEVICE: 00544 /* We don't support stopping yet */ 00545 Status = STATUS_UNSUCCESSFUL; 00546 Irp->IoStatus.Status = Status; 00547 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00548 return Status; 00549 00550 case IRP_MN_STOP_DEVICE: 00551 /* We can't fail this one so we fail the QUERY_STOP request that precedes it */ 00552 break; 00553 #if 0 00554 case IRP_MN_SURPRISE_REMOVAL: 00555 Status = STATUS_NOT_IMPLEMENTED; 00556 break; 00557 #endif 00558 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 00559 break; 00560 case IRP_MN_REMOVE_DEVICE: 00561 /* Detach the device object from the device stack */ 00562 IoDetachDevice(DeviceExtension->Ldo); 00563 00564 /* Delete the device object */ 00565 IoDeleteDevice(DeviceObject); 00566 00567 /* Return success */ 00568 Status = STATUS_SUCCESS; 00569 break; 00570 default: 00571 DPRINT1("Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction); 00572 break; 00573 } 00574 00575 Irp->IoStatus.Status = Status; 00576 IoSkipCurrentIrpStackLocation(Irp); 00577 Status = IoCallDriver(DeviceExtension->Ldo, Irp); 00578 00579 DPRINT("Leaving. Status 0x%X\n", Status); 00580 00581 return Status; 00582 } 00583 00584 00585 NTSTATUS 00586 FdoPowerControl( 00587 PDEVICE_OBJECT DeviceObject, 00588 PIRP Irp) 00589 /* 00590 * FUNCTION: Handle power management IRPs for the PCI device object 00591 * ARGUMENTS: 00592 * DeviceObject = Pointer to functional device object of the PCI driver 00593 * Irp = Pointer to IRP that should be handled 00594 * RETURNS: 00595 * Status 00596 */ 00597 { 00598 PIO_STACK_LOCATION IrpSp; 00599 NTSTATUS Status; 00600 00601 DPRINT("Called\n"); 00602 00603 IrpSp = IoGetCurrentIrpStackLocation(Irp); 00604 00605 switch (IrpSp->MinorFunction) { 00606 case IRP_MN_SET_POWER: 00607 Status = FdoSetPower(DeviceObject, Irp, IrpSp); 00608 break; 00609 00610 default: 00611 DPRINT("Unknown IOCTL 0x%X\n", IrpSp->MinorFunction); 00612 Status = STATUS_NOT_IMPLEMENTED; 00613 break; 00614 } 00615 00616 if (Status != STATUS_PENDING) { 00617 Irp->IoStatus.Status = Status; 00618 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00619 } 00620 00621 DPRINT("Leaving. Status 0x%X\n", Status); 00622 00623 return Status; 00624 } 00625 00626 /* EOF */ Generated on Sun May 27 2012 04:27:26 for ReactOS by
1.7.6.1
|