1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: Parallel Port Function Driver 4 * FILE: drivers/parallel/parport/fdo.c 5 * PURPOSE: FDO functions 6 */ 7 8 #include "parport.h" 9 10 /* FUNCTIONS ****************************************************************/ 11 12 NTSTATUS 13 NTAPI 14 AddDeviceInternal(IN PDRIVER_OBJECT DriverObject, 15 IN PDEVICE_OBJECT Pdo, 16 IN PULONG pLptPortNumber OPTIONAL, 17 OUT PDEVICE_OBJECT* pFdo OPTIONAL) 18 { 19 PFDO_DEVICE_EXTENSION DeviceExtension = NULL; 20 PDEVICE_OBJECT Fdo = NULL; 21 WCHAR DeviceNameBuffer[32]; 22 UNICODE_STRING DeviceName; 23 NTSTATUS Status; 24 25 DPRINT("AddDeviceInternal()\n"); 26 27 ASSERT(DriverObject); 28 ASSERT(Pdo); 29 30 /* Create new device object */ 31 swprintf(DeviceNameBuffer, 32 L"\\Device\\ParallelPort%lu", 33 IoGetConfigurationInformation()->ParallelCount); 34 RtlInitUnicodeString(&DeviceName, 35 DeviceNameBuffer); 36 37 Status = IoCreateDevice(DriverObject, 38 sizeof(FDO_DEVICE_EXTENSION), 39 &DeviceName, 40 FILE_DEVICE_PARALLEL_PORT, 41 FILE_DEVICE_SECURE_OPEN, 42 FALSE, 43 &Fdo); 44 if (!NT_SUCCESS(Status)) 45 { 46 DPRINT1("IoCreateDevice() failed (Status 0x%08lx)\n", Status); 47 Fdo = NULL; 48 goto done; 49 } 50 51 DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension; 52 RtlZeroMemory(DeviceExtension, 53 sizeof(FDO_DEVICE_EXTENSION)); 54 55 DeviceExtension->Common.IsFDO = TRUE; 56 DeviceExtension->Common.PnpState = dsStopped; 57 58 DeviceExtension->PortNumber = IoGetConfigurationInformation()->ParallelCount++; 59 DeviceExtension->Pdo = Pdo; 60 61 Status = IoAttachDeviceToDeviceStackSafe(Fdo, 62 Pdo, 63 &DeviceExtension->LowerDevice); 64 if (!NT_SUCCESS(Status)) 65 { 66 DPRINT1("IoAttachDeviceToDeviceStackSafe() failed (Status 0x%08lx)\n", Status); 67 goto done; 68 } 69 70 if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE) 71 Fdo->Flags |= DO_POWER_PAGABLE; 72 73 if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO) 74 Fdo->Flags |= DO_BUFFERED_IO; 75 76 if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO) 77 Fdo->Flags |= DO_DIRECT_IO; 78 79 /* Choose default strategy */ 80 if ((Fdo->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)) == 0) 81 Fdo->Flags |= DO_BUFFERED_IO; 82 83 Fdo->Flags &= ~DO_DEVICE_INITIALIZING; 84 85 if (pFdo) 86 { 87 *pFdo = Fdo; 88 } 89 90 return STATUS_SUCCESS; 91 92 done: 93 if (Fdo) 94 { 95 IoDeleteDevice(Fdo); 96 } 97 98 return Status; 99 } 100 101 102 NTSTATUS 103 NTAPI 104 FdoStartDevice(IN PDEVICE_OBJECT DeviceObject, 105 IN PCM_RESOURCE_LIST ResourceList, 106 IN PCM_RESOURCE_LIST ResourceListTranslated) 107 { 108 PFDO_DEVICE_EXTENSION DeviceExtension; 109 ULONG i; 110 // ULONG Vector = 0; 111 // KIRQL Dirql = 0; 112 // KAFFINITY Affinity = 0; 113 // KINTERRUPT_MODE InterruptMode = Latched; 114 // BOOLEAN ShareInterrupt = TRUE; 115 116 DPRINT("FdoStartDevice ()\n"); 117 118 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 119 120 ASSERT(DeviceExtension); 121 ASSERT(DeviceExtension->Common.IsFDO == TRUE); 122 123 if (!ResourceList) 124 { 125 DPRINT1("No allocated resources sent to driver\n"); 126 return STATUS_INSUFFICIENT_RESOURCES; 127 } 128 129 if (ResourceList->Count != 1) 130 { 131 DPRINT1("Wrong number of allocated resources sent to driver\n"); 132 return STATUS_INSUFFICIENT_RESOURCES; 133 } 134 135 if ((ResourceList->List[0].PartialResourceList.Version != 1) || 136 (ResourceList->List[0].PartialResourceList.Revision != 1) || 137 (ResourceListTranslated->List[0].PartialResourceList.Version != 1) || 138 (ResourceListTranslated->List[0].PartialResourceList.Revision != 1)) 139 { 140 DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n", 141 ResourceList->List[0].PartialResourceList.Version, 142 ResourceList->List[0].PartialResourceList.Revision, 143 ResourceListTranslated->List[0].PartialResourceList.Version, 144 ResourceListTranslated->List[0].PartialResourceList.Revision); 145 return STATUS_REVISION_MISMATCH; 146 } 147 148 DeviceExtension->BaseAddress = 0; 149 150 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 151 { 152 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 153 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i]; 154 155 switch (PartialDescriptor->Type) 156 { 157 case CmResourceTypePort: 158 DPRINT("Port: BaseAddress 0x%lx Length %lu\n", 159 PartialDescriptor->u.Port.Start.u.LowPart, 160 PartialDescriptor->u.Port.Length); 161 162 if (DeviceExtension->BaseAddress == 0) 163 { 164 if (PartialDescriptor->u.Port.Length < 3) 165 return STATUS_INSUFFICIENT_RESOURCES; 166 167 DeviceExtension->BaseAddress = PartialDescriptor->u.Port.Start.u.LowPart; 168 } 169 break; 170 171 case CmResourceTypeInterrupt: 172 DPRINT("Interrupt: Level %lu Vector %lu\n", 173 PartialDescriptorTranslated->u.Interrupt.Level, 174 PartialDescriptorTranslated->u.Interrupt.Vector); 175 176 // Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level; 177 // Vector = PartialDescriptorTranslated->u.Interrupt.Vector; 178 // Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity; 179 180 // if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) 181 // InterruptMode = Latched; 182 // else 183 // InterruptMode = LevelSensitive; 184 185 // ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared); 186 break; 187 188 default: 189 DPRINT1("Other resource: \n"); 190 break; 191 } 192 } 193 194 DPRINT("New LPT port: Base 0x%lx\n", 195 DeviceExtension->BaseAddress); 196 197 if (!DeviceExtension->BaseAddress) 198 return STATUS_INSUFFICIENT_RESOURCES; 199 200 #if 0 201 if (!Dirql) 202 return STATUS_INSUFFICIENT_RESOURCES; 203 #endif 204 205 DeviceExtension->Common.PnpState = dsStarted; 206 207 208 /* We don't really care if the call succeeded or not... */ 209 210 return STATUS_SUCCESS; 211 } 212 213 214 static 215 NTSTATUS 216 FdoCreateRawParallelPdo( 217 IN PDEVICE_OBJECT DeviceObject) 218 { 219 PFDO_DEVICE_EXTENSION FdoDeviceExtension; 220 PPDO_DEVICE_EXTENSION PdoDeviceExtension = NULL; 221 PDEVICE_OBJECT Pdo = NULL; 222 WCHAR DeviceNameBuffer[32]; 223 WCHAR LinkNameBuffer[32]; 224 WCHAR LptPortBuffer[32]; 225 UNICODE_STRING DeviceName; 226 UNICODE_STRING LinkName; 227 UNICODE_STRING LptPort; 228 OBJECT_ATTRIBUTES ObjectAttributes; 229 UNICODE_STRING KeyName; 230 HANDLE KeyHandle; 231 NTSTATUS Status; 232 233 DPRINT("FdoCreateRawParallelPdo()\n"); 234 235 FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 236 237 /* Create new device object */ 238 swprintf(DeviceNameBuffer, 239 L"\\Device\\Parallel%lu", 240 FdoDeviceExtension->PortNumber); 241 RtlInitUnicodeString(&DeviceName, 242 DeviceNameBuffer); 243 244 Status = IoCreateDevice(DeviceObject->DriverObject, 245 sizeof(PDO_DEVICE_EXTENSION), 246 &DeviceName, 247 FILE_DEVICE_CONTROLLER, 248 0, 249 FALSE, 250 &Pdo); 251 if (!NT_SUCCESS(Status)) 252 { 253 DPRINT1("IoCreateDevice() failed with status 0x%08x\n", Status); 254 goto done; 255 } 256 257 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; 258 Pdo->Flags |= DO_POWER_PAGABLE; 259 260 PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension; 261 RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); 262 263 PdoDeviceExtension->Common.IsFDO = FALSE; 264 PdoDeviceExtension->Common.PnpState = dsStopped; 265 266 Pdo->StackSize = DeviceObject->StackSize + 1; 267 268 FdoDeviceExtension->AttachedRawPdo = Pdo; 269 PdoDeviceExtension->AttachedFdo = DeviceObject; 270 271 PdoDeviceExtension->PortNumber = FdoDeviceExtension->PortNumber; 272 PdoDeviceExtension->LptPort = PdoDeviceExtension->PortNumber + 1; 273 274 275 /* Create link \DosDevices\LPTX -> \Device\ParallelY */ 276 swprintf(LinkNameBuffer, L"\\DosDevices\\LPT%lu", PdoDeviceExtension->LptPort); 277 RtlInitUnicodeString(&LinkName, LinkNameBuffer); 278 Status = IoCreateSymbolicLink(&LinkName, 279 &DeviceName); 280 if (!NT_SUCCESS(Status)) 281 { 282 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08x\n", Status); 283 goto done; 284 } 285 286 swprintf(LptPortBuffer, L"LPT%lu", PdoDeviceExtension->LptPort); 287 RtlInitUnicodeString(&LptPort, LptPortBuffer); 288 289 /* Write an entry value under HKLM\HARDWARE\DeviceMap\PARALLEL PORTS. */ 290 /* This step is not mandatory, so do not exit in case of error. */ 291 RtlInitUnicodeString(&KeyName, 292 L"\\Registry\\Machine\\HARDWARE\\DeviceMap\\PARALLEL PORTS"); 293 InitializeObjectAttributes(&ObjectAttributes, 294 &KeyName, 295 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 296 NULL, 297 NULL); 298 299 Status = ZwCreateKey(&KeyHandle, 300 KEY_SET_VALUE, 301 &ObjectAttributes, 302 0, 303 NULL, 304 REG_OPTION_VOLATILE, 305 NULL); 306 if (NT_SUCCESS(Status)) 307 { 308 /* Key = \Device\Parallelx, Value = LPTx */ 309 ZwSetValueKey(KeyHandle, 310 &DeviceName, 311 0, 312 REG_SZ, 313 LptPortBuffer, 314 LptPort.Length + sizeof(WCHAR)); 315 ZwClose(KeyHandle); 316 } 317 318 Pdo->Flags |= DO_BUFFERED_IO; 319 Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 320 321 done: 322 if (!NT_SUCCESS(Status)) 323 { 324 if (Pdo) 325 { 326 ASSERT(PdoDeviceExtension); 327 IoDeleteDevice(Pdo); 328 } 329 } 330 331 return Status; 332 } 333 334 335 static 336 NTSTATUS 337 FdoQueryBusRelations( 338 IN PDEVICE_OBJECT DeviceObject, 339 IN PIRP Irp, 340 PIO_STACK_LOCATION IrpSp) 341 { 342 PFDO_DEVICE_EXTENSION DeviceExtension; 343 PDEVICE_RELATIONS DeviceRelations; 344 ULONG Size; 345 ULONG i; 346 ULONG PdoCount = 0; 347 NTSTATUS Status; 348 349 UNREFERENCED_PARAMETER(IrpSp); 350 351 DPRINT("FdoQueryBusRelations()\n"); 352 353 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 354 ASSERT(DeviceExtension->Common.IsFDO); 355 356 /* TODO: Enumerate parallel devices and create their PDOs */ 357 358 Status = FdoCreateRawParallelPdo(DeviceObject); 359 if (!NT_SUCCESS(Status)) 360 return Status; 361 362 PdoCount++; 363 364 /* Allocate a buffer for the device relations */ 365 Size = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (PdoCount - 1); 366 DeviceRelations = ExAllocatePoolWithTag(PagedPool, Size, PARPORT_TAG); 367 if (DeviceRelations == NULL) 368 return STATUS_INSUFFICIENT_RESOURCES; 369 370 /* Fill the buffer */ 371 i = 0; 372 ObReferenceObject(DeviceExtension->AttachedRawPdo); 373 DeviceRelations->Objects[i] = DeviceExtension->AttachedRawPdo; 374 DeviceRelations->Count = 1; 375 376 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; 377 378 DPRINT("Done\n"); 379 380 return STATUS_SUCCESS; 381 } 382 383 384 /* PUBLIC FUNCTIONS *********************************************************/ 385 386 NTSTATUS 387 NTAPI 388 AddDevice(IN PDRIVER_OBJECT DriverObject, 389 IN PDEVICE_OBJECT Pdo) 390 { 391 DPRINT("AddDevice(%p %p)\n", DriverObject, Pdo); 392 393 /* Serial.sys is a legacy driver. AddDevice is called once 394 * with a NULL Pdo just after the driver initialization. 395 * Detect this case and return success. 396 */ 397 if (Pdo == NULL) 398 return STATUS_SUCCESS; 399 400 /* We have here a PDO not null. It represents a real serial 401 * port. So call the internal AddDevice function. 402 */ 403 return AddDeviceInternal(DriverObject, Pdo, NULL, NULL); 404 } 405 406 407 NTSTATUS 408 NTAPI 409 FdoCreate(IN PDEVICE_OBJECT DeviceObject, 410 IN PIRP Irp) 411 { 412 PFDO_DEVICE_EXTENSION DeviceExtension; 413 PIO_STACK_LOCATION Stack; 414 NTSTATUS Status = STATUS_SUCCESS; 415 416 DPRINT("FdoCreate()\n"); 417 418 Stack = IoGetCurrentIrpStackLocation(Irp); 419 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 420 421 if (Stack->Parameters.Create.Options & FILE_DIRECTORY_FILE) 422 { 423 DPRINT1("Not a directory\n"); 424 Status = STATUS_NOT_A_DIRECTORY; 425 goto done; 426 } 427 428 DPRINT("Open parallel port %lu: successful\n", DeviceExtension->PortNumber); 429 DeviceExtension->OpenCount++; 430 431 done: 432 Irp->IoStatus.Status = Status; 433 Irp->IoStatus.Information = 0; 434 IoCompleteRequest(Irp, IO_NO_INCREMENT); 435 436 return Status; 437 } 438 439 440 NTSTATUS 441 NTAPI 442 FdoClose(IN PDEVICE_OBJECT DeviceObject, 443 IN PIRP Irp) 444 { 445 PFDO_DEVICE_EXTENSION pDeviceExtension; 446 447 DPRINT("FdoClose()\n"); 448 449 pDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 450 pDeviceExtension->OpenCount--; 451 452 Irp->IoStatus.Information = 0; 453 Irp->IoStatus.Status = STATUS_SUCCESS; 454 IoCompleteRequest(Irp, IO_NO_INCREMENT); 455 456 return STATUS_SUCCESS; 457 } 458 459 460 NTSTATUS 461 NTAPI 462 FdoCleanup(IN PDEVICE_OBJECT DeviceObject, 463 IN PIRP Irp) 464 { 465 DPRINT("FdoCleanup()\n"); 466 467 Irp->IoStatus.Information = 0; 468 Irp->IoStatus.Status = STATUS_SUCCESS; 469 IoCompleteRequest(Irp, IO_NO_INCREMENT); 470 471 return STATUS_SUCCESS; 472 } 473 474 475 NTSTATUS 476 NTAPI 477 FdoRead(IN PDEVICE_OBJECT DeviceObject, 478 IN PIRP Irp) 479 { 480 DPRINT("FdoRead()\n"); 481 482 Irp->IoStatus.Information = 0; 483 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 484 IoCompleteRequest(Irp, IO_NO_INCREMENT); 485 return STATUS_NOT_SUPPORTED; 486 } 487 488 489 NTSTATUS 490 NTAPI 491 FdoWrite(IN PDEVICE_OBJECT DeviceObject, 492 IN PIRP Irp) 493 { 494 DPRINT("FdoWrite()\n"); 495 496 Irp->IoStatus.Information = 0; 497 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 498 IoCompleteRequest(Irp, IO_NO_INCREMENT); 499 return STATUS_NOT_SUPPORTED; 500 } 501 502 503 NTSTATUS 504 NTAPI 505 FdoPnp(IN PDEVICE_OBJECT DeviceObject, 506 IN PIRP Irp) 507 { 508 PFDO_DEVICE_EXTENSION FdoExtension; 509 ULONG MinorFunction; 510 PIO_STACK_LOCATION Stack; 511 ULONG_PTR Information = 0; 512 NTSTATUS Status; 513 514 DPRINT("FdoPnp()\n"); 515 516 Stack = IoGetCurrentIrpStackLocation(Irp); 517 MinorFunction = Stack->MinorFunction; 518 519 switch (MinorFunction) 520 { 521 /* FIXME: do all these minor functions 522 IRP_MN_QUERY_REMOVE_DEVICE 0x1 523 IRP_MN_REMOVE_DEVICE 0x2 524 { 525 TRACE_(SERIAL, "IRP_MJ_PNP / IRP_MN_REMOVE_DEVICE\n"); 526 IoAcquireRemoveLock 527 IoReleaseRemoveLockAndWait 528 pass request to DeviceExtension-LowerDriver 529 disable interface 530 IoDeleteDevice(Fdo) and/or IoDetachDevice 531 break; 532 } 533 IRP_MN_CANCEL_REMOVE_DEVICE 0x3 534 IRP_MN_STOP_DEVICE 0x4 535 IRP_MN_QUERY_STOP_DEVICE 0x5 536 IRP_MN_CANCEL_STOP_DEVICE 0x6 537 IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations (optional) 0x7 538 IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7 539 IRP_MN_QUERY_INTERFACE (optional) 0x8 540 IRP_MN_QUERY_CAPABILITIES (optional) 0x9 541 IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional) 0xd 542 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14 543 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16 544 IRP_MN_SURPRISE_REMOVAL 0x17 545 */ 546 case IRP_MN_START_DEVICE: /* 0x0 */ 547 DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 548 549 /* Call lower driver */ 550 FdoExtension = DeviceObject->DeviceExtension; 551 Status = STATUS_UNSUCCESSFUL; 552 553 ASSERT(FdoExtension->Common.PnpState == dsStopped); 554 555 if (IoForwardIrpSynchronously(FdoExtension->LowerDevice, Irp)) 556 { 557 Status = Irp->IoStatus.Status; 558 if (NT_SUCCESS(Status)) 559 { 560 Status = FdoStartDevice(DeviceObject, 561 Stack->Parameters.StartDevice.AllocatedResources, 562 Stack->Parameters.StartDevice.AllocatedResourcesTranslated); 563 } 564 } 565 break; 566 567 case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */ 568 switch (Stack->Parameters.QueryDeviceRelations.Type) 569 { 570 case BusRelations: 571 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); 572 Status = FdoQueryBusRelations(DeviceObject, Irp, Stack); 573 Irp->IoStatus.Status = Status; 574 IoCompleteRequest(Irp, IO_NO_INCREMENT); 575 return Status; 576 577 case RemovalRelations: 578 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n"); 579 return ForwardIrpAndForget(DeviceObject, Irp); 580 581 default: 582 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 583 Stack->Parameters.QueryDeviceRelations.Type); 584 return ForwardIrpAndForget(DeviceObject, Irp); 585 } 586 break; 587 588 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0xd */ 589 DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); 590 return ForwardIrpAndForget(DeviceObject, Irp); 591 592 default: 593 DPRINT("Unknown minor function 0x%x\n", MinorFunction); 594 return ForwardIrpAndForget(DeviceObject, Irp); 595 } 596 597 Irp->IoStatus.Information = Information; 598 Irp->IoStatus.Status = Status; 599 IoCompleteRequest(Irp, IO_NO_INCREMENT); 600 601 return Status; 602 } 603 604 605 NTSTATUS 606 NTAPI 607 FdoPower(IN PDEVICE_OBJECT DeviceObject, 608 IN PIRP Irp) 609 { 610 PDEVICE_OBJECT LowerDevice; 611 612 DPRINT("FdoPower()\n"); 613 614 LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice; 615 PoStartNextPowerIrp(Irp); 616 IoSkipCurrentIrpStackLocation(Irp); 617 return PoCallDriver(LowerDevice, Irp); 618 } 619 620 /* EOF */ 621