1 /* 2 * PROJECT: ReactOS Floppy Disk Controller Driver 3 * LICENSE: GNU GPLv2 only as published by the Free Software Foundation 4 * FILE: drivers/storage/fdc/fdc/fdo.c 5 * PURPOSE: Functional Device Object routines 6 * PROGRAMMERS: Eric Kohl 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "fdc.h" 12 13 #include <stdio.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* FUNCTIONS ******************************************************************/ 18 19 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion; 20 21 static 22 NTSTATUS 23 NTAPI 24 ForwardIrpAndWaitCompletion( 25 IN PDEVICE_OBJECT DeviceObject, 26 IN PIRP Irp, 27 IN PVOID Context) 28 { 29 if (Irp->PendingReturned) 30 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); 31 return STATUS_MORE_PROCESSING_REQUIRED; 32 } 33 34 35 NTSTATUS 36 ForwardIrpAndWait( 37 IN PDEVICE_OBJECT DeviceObject, 38 IN PIRP Irp) 39 { 40 PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice; 41 KEVENT Event; 42 NTSTATUS Status; 43 44 ASSERT(LowerDevice); 45 46 KeInitializeEvent(&Event, NotificationEvent, FALSE); 47 IoCopyCurrentIrpStackLocationToNext(Irp); 48 49 DPRINT("Calling lower device %p\n", LowerDevice); 50 IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE); 51 52 Status = IoCallDriver(LowerDevice, Irp); 53 if (Status == STATUS_PENDING) 54 { 55 Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); 56 if (NT_SUCCESS(Status)) 57 Status = Irp->IoStatus.Status; 58 } 59 60 return Status; 61 } 62 63 64 NTSTATUS 65 NTAPI 66 ForwardIrpAndForget( 67 IN PDEVICE_OBJECT DeviceObject, 68 IN PIRP Irp) 69 { 70 PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice; 71 72 ASSERT(LowerDevice); 73 74 IoSkipCurrentIrpStackLocation(Irp); 75 return IoCallDriver(LowerDevice, Irp); 76 } 77 78 79 80 81 static 82 NTSTATUS 83 FdcFdoStartDevice( 84 IN PDEVICE_OBJECT DeviceObject, 85 IN PCM_RESOURCE_LIST ResourceList, 86 IN PCM_RESOURCE_LIST ResourceListTranslated) 87 { 88 PFDO_DEVICE_EXTENSION DeviceExtension; 89 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 90 // PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated; 91 ULONG i; 92 93 DPRINT("FdcFdoStartDevice called\n"); 94 95 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 96 97 ASSERT(DeviceExtension); 98 99 if (ResourceList == NULL || 100 ResourceListTranslated == NULL) 101 { 102 DPRINT1("No allocated resources sent to driver\n"); 103 return STATUS_INSUFFICIENT_RESOURCES; 104 } 105 106 if (ResourceList->Count != 1) 107 { 108 DPRINT1("Wrong number of allocated resources sent to driver\n"); 109 return STATUS_INSUFFICIENT_RESOURCES; 110 } 111 112 if (ResourceList->List[0].PartialResourceList.Version != 1 || 113 ResourceList->List[0].PartialResourceList.Revision != 1 || 114 ResourceListTranslated->List[0].PartialResourceList.Version != 1 || 115 ResourceListTranslated->List[0].PartialResourceList.Revision != 1) 116 { 117 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n", 118 ResourceList->List[0].PartialResourceList.Version, 119 ResourceList->List[0].PartialResourceList.Revision, 120 ResourceListTranslated->List[0].PartialResourceList.Version, 121 ResourceListTranslated->List[0].PartialResourceList.Revision); 122 return STATUS_REVISION_MISMATCH; 123 } 124 125 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 126 { 127 PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 128 // PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i]; 129 130 switch (PartialDescriptor->Type) 131 { 132 case CmResourceTypePort: 133 DPRINT("Port: 0x%lx (%lu)\n", 134 PartialDescriptor->u.Port.Start.u.LowPart, 135 PartialDescriptor->u.Port.Length); 136 if (PartialDescriptor->u.Port.Length >= 6) 137 DeviceExtension->ControllerInfo.BaseAddress = (PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart; 138 break; 139 140 case CmResourceTypeInterrupt: 141 DPRINT("Interrupt: Level %lu Vector %lu\n", 142 PartialDescriptor->u.Interrupt.Level, 143 PartialDescriptor->u.Interrupt.Vector); 144 /* 145 Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level; 146 Vector = PartialDescriptorTranslated->u.Interrupt.Vector; 147 Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity; 148 if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) 149 InterruptMode = Latched; 150 else 151 InterruptMode = LevelSensitive; 152 ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared); 153 */ 154 break; 155 156 case CmResourceTypeDma: 157 DPRINT("Dma: Channel %lu\n", 158 PartialDescriptor->u.Dma.Channel); 159 break; 160 } 161 } 162 163 return STATUS_SUCCESS; 164 } 165 166 167 static 168 NTSTATUS 169 NTAPI 170 FdcFdoConfigCallback( 171 PVOID Context, 172 PUNICODE_STRING PathName, 173 INTERFACE_TYPE BusType, 174 ULONG BusNumber, 175 PKEY_VALUE_FULL_INFORMATION *BusInformation, 176 CONFIGURATION_TYPE ControllerType, 177 ULONG ControllerNumber, 178 PKEY_VALUE_FULL_INFORMATION *ControllerInformation, 179 CONFIGURATION_TYPE PeripheralType, 180 ULONG PeripheralNumber, 181 PKEY_VALUE_FULL_INFORMATION *PeripheralInformation) 182 { 183 PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor; 184 PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor; 185 PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor; 186 PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor; 187 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 188 PCM_FLOPPY_DEVICE_DATA FloppyDeviceData; 189 PFDO_DEVICE_EXTENSION DeviceExtension; 190 PDRIVE_INFO DriveInfo; 191 BOOLEAN ControllerFound = FALSE; 192 ULONG i; 193 194 DPRINT("FdcFdoConfigCallback() called\n"); 195 196 DeviceExtension = (PFDO_DEVICE_EXTENSION)Context; 197 198 /* Get the controller resources */ 199 ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData]; 200 ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor + 201 ControllerFullDescriptor->DataOffset); 202 203 for(i = 0; i < ControllerResourceDescriptor->PartialResourceList.Count; i++) 204 { 205 PartialDescriptor = &ControllerResourceDescriptor->PartialResourceList.PartialDescriptors[i]; 206 207 if (PartialDescriptor->Type == CmResourceTypePort) 208 { 209 if ((PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart == DeviceExtension->ControllerInfo.BaseAddress) 210 ControllerFound = TRUE; 211 } 212 } 213 214 /* Leave, if the enumerated controller is not the one represented by the FDO */ 215 if (ControllerFound == FALSE) 216 return STATUS_SUCCESS; 217 218 /* Get the peripheral resources */ 219 PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData]; 220 PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor + 221 PeripheralFullDescriptor->DataOffset); 222 223 /* learn about drives attached to controller */ 224 for(i = 0; i < PeripheralResourceDescriptor->PartialResourceList.Count; i++) 225 { 226 PartialDescriptor = &PeripheralResourceDescriptor->PartialResourceList.PartialDescriptors[i]; 227 228 if (PartialDescriptor->Type != CmResourceTypeDeviceSpecific) 229 continue; 230 231 FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)(PartialDescriptor + 1); 232 233 DriveInfo = &DeviceExtension->ControllerInfo.DriveInfo[DeviceExtension->ControllerInfo.NumberOfDrives]; 234 235 DriveInfo->ControllerInfo = &DeviceExtension->ControllerInfo; 236 DriveInfo->UnitNumber = DeviceExtension->ControllerInfo.NumberOfDrives; 237 DriveInfo->PeripheralNumber = PeripheralNumber; 238 239 DriveInfo->FloppyDeviceData.MaxDensity = FloppyDeviceData->MaxDensity; 240 DriveInfo->FloppyDeviceData.MountDensity = FloppyDeviceData->MountDensity; 241 DriveInfo->FloppyDeviceData.StepRateHeadUnloadTime = FloppyDeviceData->StepRateHeadUnloadTime; 242 DriveInfo->FloppyDeviceData.HeadLoadTime = FloppyDeviceData->HeadLoadTime; 243 DriveInfo->FloppyDeviceData.MotorOffTime = FloppyDeviceData->MotorOffTime; 244 DriveInfo->FloppyDeviceData.SectorLengthCode = FloppyDeviceData->SectorLengthCode; 245 DriveInfo->FloppyDeviceData.SectorPerTrack = FloppyDeviceData->SectorPerTrack; 246 DriveInfo->FloppyDeviceData.ReadWriteGapLength = FloppyDeviceData->ReadWriteGapLength; 247 DriveInfo->FloppyDeviceData.FormatGapLength = FloppyDeviceData->FormatGapLength; 248 DriveInfo->FloppyDeviceData.FormatFillCharacter = FloppyDeviceData->FormatFillCharacter; 249 DriveInfo->FloppyDeviceData.HeadSettleTime = FloppyDeviceData->HeadSettleTime; 250 DriveInfo->FloppyDeviceData.MotorSettleTime = FloppyDeviceData->MotorSettleTime; 251 DriveInfo->FloppyDeviceData.MaximumTrackValue = FloppyDeviceData->MaximumTrackValue; 252 DriveInfo->FloppyDeviceData.DataTransferLength = FloppyDeviceData->DataTransferLength; 253 254 /* Once it's all set up, acknowledge its existence in the controller info object */ 255 DeviceExtension->ControllerInfo.NumberOfDrives++; 256 } 257 258 DeviceExtension->ControllerInfo.Populated = TRUE; 259 260 DPRINT("Detected %lu floppy drives!\n", 261 DeviceExtension->ControllerInfo.NumberOfDrives); 262 263 return STATUS_SUCCESS; 264 } 265 266 267 static 268 NTSTATUS 269 PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs) 270 { 271 WCHAR Buffer[256]; 272 UNICODE_STRING BufferU; 273 ULONG Index; 274 275 Index = 0; 276 Index += swprintf(&Buffer[Index], 277 L"FDC\\GENERIC_FLOPPY_DRIVE"); 278 Index++; 279 280 Buffer[Index] = UNICODE_NULL; 281 282 BufferU.Length = BufferU.MaximumLength = (USHORT) Index * sizeof(WCHAR); 283 BufferU.Buffer = Buffer; 284 285 return DuplicateUnicodeString(0, &BufferU, HardwareIDs); 286 } 287 288 289 static 290 NTSTATUS 291 PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs) 292 { 293 WCHAR Buffer[256]; 294 UNICODE_STRING BufferU; 295 ULONG Index; 296 297 Index = 0; 298 Index += swprintf(&Buffer[Index], 299 L"GenFloppyDisk"); 300 Index++; 301 302 Buffer[Index] = UNICODE_NULL; 303 304 BufferU.Length = BufferU.MaximumLength = (USHORT)Index * sizeof(WCHAR); 305 BufferU.Buffer = Buffer; 306 307 return DuplicateUnicodeString(0, &BufferU, CompatibleIDs); 308 } 309 310 311 static 312 NTSTATUS 313 PciCreateInstanceIDString(PUNICODE_STRING InstanceID, 314 ULONG PeripheralNumber) 315 { 316 WCHAR Buffer[3]; 317 318 swprintf(Buffer, L"%02X", PeripheralNumber & 0xff); 319 320 return RtlCreateUnicodeString(InstanceID, Buffer) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 321 } 322 323 324 static 325 NTSTATUS 326 FdcFdoQueryBusRelations( 327 IN PDEVICE_OBJECT DeviceObject, 328 OUT PDEVICE_RELATIONS *DeviceRelations) 329 { 330 PFDO_DEVICE_EXTENSION FdoDeviceExtension; 331 PPDO_DEVICE_EXTENSION PdoDeviceExtension; 332 INTERFACE_TYPE InterfaceType = Isa; 333 CONFIGURATION_TYPE ControllerType = DiskController; 334 CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral; 335 PDEVICE_RELATIONS Relations; 336 PDRIVE_INFO DriveInfo; 337 PDEVICE_OBJECT Pdo; 338 WCHAR DeviceNameBuffer[80]; 339 UNICODE_STRING DeviceName; 340 ULONG DeviceNumber = 0; 341 ULONG Size; 342 ULONG i; 343 NTSTATUS Status; 344 345 DPRINT("FdcFdoQueryBusRelations() called\n"); 346 347 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 348 349 Status = IoQueryDeviceDescription(&InterfaceType, 350 NULL, 351 &ControllerType, 352 NULL, 353 &PeripheralType, 354 NULL, 355 FdcFdoConfigCallback, 356 FdoDeviceExtension); 357 if (!NT_SUCCESS(Status) && (Status != STATUS_NO_MORE_ENTRIES)) 358 return Status; 359 360 Size = sizeof(DEVICE_RELATIONS) + 361 sizeof(Relations->Objects) * (FdoDeviceExtension->ControllerInfo.NumberOfDrives - 1); 362 Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size); 363 if (Relations == NULL) 364 { 365 return STATUS_INSUFFICIENT_RESOURCES; 366 } 367 368 Relations->Count = FdoDeviceExtension->ControllerInfo.NumberOfDrives; 369 370 for (i = 0; i < FdoDeviceExtension->ControllerInfo.NumberOfDrives; i++) 371 { 372 DriveInfo = &FdoDeviceExtension->ControllerInfo.DriveInfo[i]; 373 374 if (DriveInfo->DeviceObject == NULL) 375 { 376 do 377 { 378 swprintf(DeviceNameBuffer, L"\\Device\\FloppyPDO%lu", DeviceNumber++); 379 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer); 380 DPRINT("Device name: %S\n", DeviceNameBuffer); 381 382 /* Create physical device object */ 383 Status = IoCreateDevice(FdoDeviceExtension->Common.DeviceObject->DriverObject, 384 sizeof(PDO_DEVICE_EXTENSION), 385 &DeviceName, 386 FILE_DEVICE_MASS_STORAGE, 387 FILE_DEVICE_SECURE_OPEN, 388 FALSE, 389 &Pdo); 390 } 391 while (Status == STATUS_OBJECT_NAME_COLLISION); 392 393 if (!NT_SUCCESS(Status)) 394 { 395 DPRINT1("PDO creation failed (Status 0x%08lx)\n", Status); 396 goto done; 397 } 398 399 DPRINT("PDO created: %S\n", DeviceNameBuffer); 400 401 DriveInfo->DeviceObject = Pdo; 402 403 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension; 404 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); 405 406 PdoDeviceExtension->Common.IsFDO = FALSE; 407 PdoDeviceExtension->Common.DeviceObject = Pdo; 408 409 PdoDeviceExtension->Fdo = FdoDeviceExtension->Common.DeviceObject; 410 PdoDeviceExtension->DriveInfo = DriveInfo; 411 412 Pdo->Flags |= DO_DIRECT_IO; 413 Pdo->Flags |= DO_POWER_PAGABLE; 414 Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 415 416 /* Add Device ID string */ 417 RtlCreateUnicodeString(&PdoDeviceExtension->DeviceId, 418 L"FDC\\GENERIC_FLOPPY_DRIVE"); 419 DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceId.Buffer); 420 421 /* Add Hardware IDs string */ 422 Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIds); 423 if (!NT_SUCCESS(Status)) 424 { 425 // ErrorStatus = Status; 426 // ErrorOccurred = TRUE; 427 break; 428 } 429 430 /* Add Compatible IDs string */ 431 Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIds); 432 if (!NT_SUCCESS(Status)) 433 { 434 // ErrorStatus = Status; 435 // ErrorOccurred = TRUE; 436 break; 437 } 438 439 /* Add Instance ID string */ 440 Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceId, 441 DriveInfo->PeripheralNumber); 442 if (!NT_SUCCESS(Status)) 443 { 444 // ErrorStatus = Status; 445 // ErrorOccurred = TRUE; 446 break; 447 } 448 449 #if 0 450 /* Add device description string */ 451 Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device); 452 if (!NT_SUCCESS(Status)) 453 { 454 // ErrorStatus = Status; 455 // ErrorOccurred = TRUE; 456 break; 457 } 458 459 /* Add device location string */ 460 Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device); 461 if (!NT_SUCCESS(Status)) 462 { 463 // ErrorStatus = Status; 464 // ErrorOccurred = TRUE; 465 break; 466 } 467 #endif 468 } 469 470 ObReferenceObject(DriveInfo->DeviceObject); 471 Relations->Objects[i] = DriveInfo->DeviceObject; 472 } 473 474 done: 475 if (NT_SUCCESS(Status)) 476 { 477 *DeviceRelations = Relations; 478 } 479 else 480 { 481 if (Relations != NULL) 482 ExFreePool(Relations); 483 } 484 485 return Status; 486 } 487 488 489 NTSTATUS 490 NTAPI 491 FdcFdoPnp( 492 IN PDEVICE_OBJECT DeviceObject, 493 IN PIRP Irp) 494 { 495 PIO_STACK_LOCATION IrpSp; 496 PDEVICE_RELATIONS DeviceRelations = NULL; 497 ULONG_PTR Information = 0; 498 NTSTATUS Status = STATUS_NOT_SUPPORTED; 499 500 DPRINT("FdcFdoPnp()\n"); 501 502 IrpSp = IoGetCurrentIrpStackLocation(Irp); 503 504 switch (IrpSp->MinorFunction) 505 { 506 case IRP_MN_START_DEVICE: 507 DPRINT(" IRP_MN_START_DEVICE received\n"); 508 /* Call lower driver */ 509 Status = ForwardIrpAndWait(DeviceObject, Irp); 510 if (NT_SUCCESS(Status)) 511 { 512 Status = FdcFdoStartDevice(DeviceObject, 513 IrpSp->Parameters.StartDevice.AllocatedResources, 514 IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated); 515 } 516 break; 517 518 case IRP_MN_QUERY_REMOVE_DEVICE: 519 DPRINT(" IRP_MN_QUERY_REMOVE_DEVICE\n"); 520 break; 521 522 case IRP_MN_REMOVE_DEVICE: 523 DPRINT(" IRP_MN_REMOVE_DEVICE received\n"); 524 break; 525 526 case IRP_MN_CANCEL_REMOVE_DEVICE: 527 DPRINT(" IRP_MN_CANCEL_REMOVE_DEVICE\n"); 528 break; 529 530 case IRP_MN_STOP_DEVICE: 531 DPRINT(" IRP_MN_STOP_DEVICE received\n"); 532 break; 533 534 case IRP_MN_QUERY_STOP_DEVICE: 535 DPRINT(" IRP_MN_QUERY_STOP_DEVICE received\n"); 536 break; 537 538 case IRP_MN_CANCEL_STOP_DEVICE: 539 DPRINT(" IRP_MN_CANCEL_STOP_DEVICE\n"); 540 break; 541 542 case IRP_MN_QUERY_DEVICE_RELATIONS: 543 DPRINT(" IRP_MN_QUERY_DEVICE_RELATIONS\n"); 544 545 switch (IrpSp->Parameters.QueryDeviceRelations.Type) 546 { 547 case BusRelations: 548 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); 549 Status = FdcFdoQueryBusRelations(DeviceObject, &DeviceRelations); 550 Information = (ULONG_PTR)DeviceRelations; 551 break; 552 553 case RemovalRelations: 554 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n"); 555 return ForwardIrpAndForget(DeviceObject, Irp); 556 557 default: 558 DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 559 IrpSp->Parameters.QueryDeviceRelations.Type); 560 return ForwardIrpAndForget(DeviceObject, Irp); 561 } 562 break; 563 564 case IRP_MN_SURPRISE_REMOVAL: 565 DPRINT(" IRP_MN_SURPRISE_REMOVAL received\n"); 566 break; 567 568 default: 569 DPRINT(" Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction); 570 return ForwardIrpAndForget(DeviceObject, Irp); 571 } 572 573 Irp->IoStatus.Information = Information; 574 Irp->IoStatus.Status = Status; 575 IoCompleteRequest(Irp, IO_NO_INCREMENT); 576 577 return Status; 578 } 579 580 /* EOF */ 581