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