1 /* 2 * PROJECT: ReactOS ISA PnP Bus driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Driver entry 5 * COPYRIGHT: Copyright 2010 Cameron Gutman <cameron.gutman@reactos.org> 6 * Copyright 2020 Hervé Poussineau <hpoussin@reactos.org> 7 */ 8 9 #include "isapnp.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 NTSTATUS 15 NTAPI 16 IsaPnpDuplicateUnicodeString( 17 IN ULONG Flags, 18 IN PCUNICODE_STRING SourceString, 19 OUT PUNICODE_STRING DestinationString) 20 { 21 if (SourceString == NULL || 22 DestinationString == NULL || 23 SourceString->Length > SourceString->MaximumLength || 24 (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) || 25 Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || 26 Flags >= 4) 27 { 28 return STATUS_INVALID_PARAMETER; 29 } 30 31 if ((SourceString->Length == 0) && 32 (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE | 33 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING))) 34 { 35 DestinationString->Length = 0; 36 DestinationString->MaximumLength = 0; 37 DestinationString->Buffer = NULL; 38 } 39 else 40 { 41 USHORT DestMaxLength = SourceString->Length; 42 43 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) 44 DestMaxLength += sizeof(UNICODE_NULL); 45 46 DestinationString->Buffer = ExAllocatePool(PagedPool, DestMaxLength); 47 if (DestinationString->Buffer == NULL) 48 return STATUS_NO_MEMORY; 49 50 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length); 51 DestinationString->Length = SourceString->Length; 52 DestinationString->MaximumLength = DestMaxLength; 53 54 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE) 55 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0; 56 } 57 58 return STATUS_SUCCESS; 59 } 60 61 static 62 NTSTATUS 63 NTAPI 64 IsaFdoCreateDeviceIDs( 65 IN PISAPNP_PDO_EXTENSION PdoExt) 66 { 67 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; 68 UNICODE_STRING TempString; 69 WCHAR TempBuffer[256]; 70 PWCHAR End; 71 NTSTATUS Status; 72 USHORT i; 73 74 TempString.Buffer = TempBuffer; 75 TempString.MaximumLength = sizeof(TempBuffer); 76 TempString.Length = 0; 77 78 /* Device ID */ 79 Status = RtlStringCbPrintfExW(TempString.Buffer, 80 TempString.MaximumLength / sizeof(WCHAR), 81 &End, 82 NULL, 0, 83 L"ISAPNP\\%.3S%04x", 84 LogDev->VendorId, 85 LogDev->ProdId); 86 if (!NT_SUCCESS(Status)) 87 return Status; 88 TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR)); 89 Status = IsaPnpDuplicateUnicodeString( 90 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 91 &TempString, 92 &PdoExt->DeviceID); 93 if (!NT_SUCCESS(Status)) 94 return Status; 95 96 /* HardwareIDs */ 97 Status = RtlStringCbPrintfExW(TempString.Buffer, 98 TempString.MaximumLength / sizeof(WCHAR), 99 &End, 100 NULL, 0, 101 L"ISAPNP\\%.3S%04x@" 102 L"*%.3S%04x@", 103 LogDev->VendorId, 104 LogDev->ProdId, 105 LogDev->VendorId, 106 LogDev->ProdId); 107 if (!NT_SUCCESS(Status)) 108 return Status; 109 TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR)); 110 Status = IsaPnpDuplicateUnicodeString( 111 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 112 &TempString, 113 &PdoExt->HardwareIDs); 114 if (!NT_SUCCESS(Status)) 115 return Status; 116 for (i = 0; i < PdoExt->HardwareIDs.Length / sizeof(WCHAR); i++) 117 if (PdoExt->HardwareIDs.Buffer[i] == '@') 118 PdoExt->HardwareIDs.Buffer[i] = UNICODE_NULL; 119 120 /* InstanceID */ 121 Status = RtlStringCbPrintfExW(TempString.Buffer, 122 TempString.MaximumLength / sizeof(WCHAR), 123 &End, 124 NULL, 0, 125 L"%X", 126 LogDev->SerialNumber); 127 if (!NT_SUCCESS(Status)) 128 return Status; 129 TempString.Length = (USHORT)((End - TempString.Buffer) * sizeof(WCHAR)); 130 Status = IsaPnpDuplicateUnicodeString( 131 RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, 132 &TempString, 133 &PdoExt->InstanceID); 134 if (!NT_SUCCESS(Status)) 135 return Status; 136 137 return STATUS_SUCCESS; 138 } 139 140 static 141 NTSTATUS 142 NTAPI 143 IsaPnpCreateLogicalDeviceRequirements( 144 _In_ PISAPNP_PDO_EXTENSION PdoExt) 145 { 146 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; 147 RTL_BITMAP IrqBitmap[RTL_NUMBER_OF(LogDev->Irq)]; 148 RTL_BITMAP DmaBitmap[RTL_NUMBER_OF(LogDev->Dma)]; 149 ULONG IrqData[RTL_NUMBER_OF(LogDev->Irq)]; 150 ULONG DmaData[RTL_NUMBER_OF(LogDev->Dma)]; 151 ULONG ResourceCount = 0; 152 ULONG ListSize, i, j; 153 BOOLEAN FirstIrq = TRUE, FirstDma = TRUE; 154 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; 155 PIO_RESOURCE_DESCRIPTOR Descriptor; 156 157 /* Count number of requirements */ 158 for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++) 159 { 160 if (!LogDev->Io[i].Description.Length) 161 break; 162 163 ResourceCount++; 164 } 165 for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) 166 { 167 if (!LogDev->Irq[i].Description.Mask) 168 break; 169 170 IrqData[i] = LogDev->Irq[i].Description.Mask; 171 RtlInitializeBitMap(&IrqBitmap[i], &IrqData[i], 16); 172 ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]); 173 174 if (LogDev->Irq[i].Description.Information & 0x4) 175 { 176 /* Add room for level sensitive */ 177 ResourceCount += RtlNumberOfSetBits(&IrqBitmap[i]); 178 } 179 } 180 if (ResourceCount == 0) 181 return STATUS_SUCCESS; 182 for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) 183 { 184 if (!LogDev->Dma[i].Description.Mask) 185 break; 186 187 DmaData[i] = LogDev->Dma[i].Description.Mask; 188 RtlInitializeBitMap(&DmaBitmap[i], &DmaData[i], 8); 189 ResourceCount += RtlNumberOfSetBits(&DmaBitmap[i]); 190 } 191 192 /* Allocate memory to store requirements */ 193 ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) 194 + ResourceCount * sizeof(IO_RESOURCE_DESCRIPTOR); 195 RequirementsList = ExAllocatePool(PagedPool, ListSize); 196 if (!RequirementsList) 197 return STATUS_NO_MEMORY; 198 199 RtlZeroMemory(RequirementsList, ListSize); 200 RequirementsList->ListSize = ListSize; 201 RequirementsList->InterfaceType = Isa; 202 RequirementsList->AlternativeLists = 1; 203 204 RequirementsList->List[0].Version = 1; 205 RequirementsList->List[0].Revision = 1; 206 RequirementsList->List[0].Count = ResourceCount; 207 208 /* Store requirements */ 209 Descriptor = RequirementsList->List[0].Descriptors; 210 for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++) 211 { 212 if (!LogDev->Io[i].Description.Length) 213 break; 214 215 DPRINT("Device.Io[%d].Information = 0x%02x\n", i, LogDev->Io[i].Description.Information); 216 DPRINT("Device.Io[%d].Minimum = 0x%02x\n", i, LogDev->Io[i].Description.Minimum); 217 DPRINT("Device.Io[%d].Maximum = 0x%02x\n", i, LogDev->Io[i].Description.Maximum); 218 DPRINT("Device.Io[%d].Alignment = 0x%02x\n", i, LogDev->Io[i].Description.Alignment); 219 DPRINT("Device.Io[%d].Length = 0x%02x\n", i, LogDev->Io[i].Description.Length); 220 221 Descriptor->Type = CmResourceTypePort; 222 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; 223 if (LogDev->Io[i].Description.Information & 0x1) 224 Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; 225 else 226 Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE; 227 Descriptor->u.Port.Length = LogDev->Io[i].Description.Length; 228 Descriptor->u.Port.Alignment = LogDev->Io[i].Description.Alignment; 229 Descriptor->u.Port.MinimumAddress.LowPart = LogDev->Io[i].Description.Minimum; 230 Descriptor->u.Port.MaximumAddress.LowPart = 231 LogDev->Io[i].Description.Maximum + LogDev->Io[i].Description.Length - 1; 232 Descriptor++; 233 } 234 for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) 235 { 236 if (!LogDev->Irq[i].Description.Mask) 237 break; 238 239 DPRINT("Device.Irq[%d].Mask = 0x%02x\n", i, LogDev->Irq[i].Description.Mask); 240 DPRINT("Device.Irq[%d].Information = 0x%02x\n", i, LogDev->Irq[i].Description.Information); 241 242 for (j = 0; j < 15; j++) 243 { 244 if (!RtlCheckBit(&IrqBitmap[i], j)) 245 continue; 246 247 if (FirstIrq) 248 FirstIrq = FALSE; 249 else 250 Descriptor->Option = IO_RESOURCE_ALTERNATIVE; 251 Descriptor->Type = CmResourceTypeInterrupt; 252 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; 253 Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j; 254 Descriptor++; 255 256 if (LogDev->Irq[i].Description.Information & 0x4) 257 { 258 /* Level interrupt */ 259 Descriptor->Option = IO_RESOURCE_ALTERNATIVE; 260 Descriptor->Type = CmResourceTypeInterrupt; 261 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; 262 Descriptor->u.Interrupt.MinimumVector = Descriptor->u.Interrupt.MaximumVector = j; 263 Descriptor++; 264 } 265 } 266 } 267 for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++) 268 { 269 if (!LogDev->Dma[i].Description.Mask) 270 break; 271 272 DPRINT("Device.Dma[%d].Mask = 0x%02x\n", i, LogDev->Dma[i].Description.Mask); 273 DPRINT("Device.Dma[%d].Information = 0x%02x\n", i, LogDev->Dma[i].Description.Information); 274 275 for (j = 0; j < 8; j++) 276 { 277 if (!RtlCheckBit(&DmaBitmap[i], j)) 278 continue; 279 280 if (FirstDma) 281 FirstDma = FALSE; 282 else 283 Descriptor->Option = IO_RESOURCE_ALTERNATIVE; 284 Descriptor->Type = CmResourceTypeDma; 285 switch (LogDev->Dma[i].Description.Information & 0x3) 286 { 287 case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break; 288 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8_AND_16; break; 289 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break; 290 default: break; 291 } 292 if (LogDev->Dma[i].Description.Information & 0x4) 293 Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER; 294 switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3) 295 { 296 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break; 297 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break; 298 case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break; 299 default: break; 300 } 301 Descriptor->u.Dma.MinimumChannel = Descriptor->u.Dma.MaximumChannel = j; 302 Descriptor++; 303 } 304 } 305 306 PdoExt->RequirementsList = RequirementsList; 307 return STATUS_SUCCESS; 308 } 309 310 static 311 NTSTATUS 312 NTAPI 313 IsaPnpCreateLogicalDeviceResources( 314 _In_ PISAPNP_PDO_EXTENSION PdoExt) 315 { 316 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; 317 ULONG ResourceCount = 0; 318 ULONG ListSize, i; 319 PCM_RESOURCE_LIST ResourceList; 320 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; 321 322 /* Count number of required resources */ 323 for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++) 324 { 325 if (LogDev->Io[i].CurrentBase) 326 ResourceCount++; 327 else 328 break; 329 } 330 for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) 331 { 332 if (LogDev->Irq[i].CurrentNo) 333 ResourceCount++; 334 else 335 break; 336 } 337 for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++) 338 { 339 if (LogDev->Dma[i].CurrentChannel != 4) 340 ResourceCount++; 341 else 342 break; 343 } 344 if (ResourceCount == 0) 345 return STATUS_SUCCESS; 346 347 /* Allocate memory to store resources */ 348 ListSize = sizeof(CM_RESOURCE_LIST) 349 + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); 350 ResourceList = ExAllocatePool(PagedPool, ListSize); 351 if (!ResourceList) 352 return STATUS_NO_MEMORY; 353 354 RtlZeroMemory(ResourceList, ListSize); 355 ResourceList->Count = 1; 356 ResourceList->List[0].InterfaceType = Isa; 357 ResourceList->List[0].PartialResourceList.Version = 1; 358 ResourceList->List[0].PartialResourceList.Revision = 1; 359 ResourceList->List[0].PartialResourceList.Count = ResourceCount; 360 361 /* Store resources */ 362 ResourceCount = 0; 363 for (i = 0; i < RTL_NUMBER_OF(LogDev->Io); i++) 364 { 365 if (!LogDev->Io[i].CurrentBase) 366 continue; 367 368 Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; 369 Descriptor->Type = CmResourceTypePort; 370 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; 371 if (LogDev->Io[i].Description.Information & 0x1) 372 Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; 373 else 374 Descriptor->Flags = CM_RESOURCE_PORT_10_BIT_DECODE; 375 Descriptor->u.Port.Length = LogDev->Io[i].Description.Length; 376 Descriptor->u.Port.Start.LowPart = LogDev->Io[i].CurrentBase; 377 } 378 for (i = 0; i < RTL_NUMBER_OF(LogDev->Irq); i++) 379 { 380 if (!LogDev->Irq[i].CurrentNo) 381 continue; 382 383 Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; 384 Descriptor->Type = CmResourceTypeInterrupt; 385 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; 386 if (LogDev->Irq[i].CurrentType & 0x01) 387 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; 388 else 389 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; 390 Descriptor->u.Interrupt.Level = LogDev->Irq[i].CurrentNo; 391 Descriptor->u.Interrupt.Vector = LogDev->Irq[i].CurrentNo; 392 Descriptor->u.Interrupt.Affinity = -1; 393 } 394 for (i = 0; i < RTL_NUMBER_OF(LogDev->Dma); i++) 395 { 396 if (LogDev->Dma[i].CurrentChannel == 4) 397 continue; 398 399 Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[ResourceCount++]; 400 Descriptor->Type = CmResourceTypeDma; 401 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; 402 switch (LogDev->Dma[i].Description.Information & 0x3) 403 { 404 case 0x0: Descriptor->Flags |= CM_RESOURCE_DMA_8; break; 405 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_8 | CM_RESOURCE_DMA_16; break; 406 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_16; break; 407 default: break; 408 } 409 if (LogDev->Dma[i].Description.Information & 0x4) 410 Descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER; 411 switch ((LogDev->Dma[i].Description.Information >> 5) & 0x3) 412 { 413 case 0x1: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A; break; 414 case 0x2: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B; break; 415 case 0x3: Descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F; break; 416 default: break; 417 } 418 Descriptor->u.Dma.Channel = LogDev->Dma[i].CurrentChannel; 419 } 420 421 PdoExt->ResourceList = ResourceList; 422 PdoExt->ResourceListSize = ListSize; 423 return STATUS_SUCCESS; 424 } 425 426 NTSTATUS 427 NTAPI 428 IsaPnpFillDeviceRelations( 429 _In_ PISAPNP_FDO_EXTENSION FdoExt, 430 _Inout_ PIRP Irp, 431 _In_ BOOLEAN IncludeDataPort) 432 { 433 PISAPNP_PDO_EXTENSION PdoExt; 434 NTSTATUS Status = STATUS_SUCCESS; 435 PLIST_ENTRY CurrentEntry; 436 PISAPNP_LOGICAL_DEVICE IsaDevice; 437 PDEVICE_RELATIONS DeviceRelations; 438 ULONG i = 0; 439 440 DeviceRelations = ExAllocatePool(NonPagedPool, 441 sizeof(DEVICE_RELATIONS) + sizeof(DEVICE_OBJECT) * FdoExt->DeviceCount); 442 if (!DeviceRelations) 443 { 444 return STATUS_NO_MEMORY; 445 } 446 447 if (IncludeDataPort) 448 { 449 DeviceRelations->Objects[i++] = FdoExt->ReadPortPdo; 450 ObReferenceObject(FdoExt->ReadPortPdo); 451 } 452 453 CurrentEntry = FdoExt->DeviceListHead.Flink; 454 while (CurrentEntry != &FdoExt->DeviceListHead) 455 { 456 IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, DeviceLink); 457 458 if (!IsaDevice->Pdo) 459 { 460 Status = IoCreateDevice(FdoExt->DriverObject, 461 sizeof(ISAPNP_PDO_EXTENSION), 462 NULL, 463 FILE_DEVICE_CONTROLLER, 464 FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME, 465 FALSE, 466 &IsaDevice->Pdo); 467 if (!NT_SUCCESS(Status)) 468 { 469 break; 470 } 471 472 IsaDevice->Pdo->Flags &= ~DO_DEVICE_INITIALIZING; 473 474 //Device->Pdo->Flags |= DO_POWER_PAGABLE; 475 476 PdoExt = IsaDevice->Pdo->DeviceExtension; 477 478 RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION)); 479 480 PdoExt->Common.IsFdo = FALSE; 481 PdoExt->Common.Self = IsaDevice->Pdo; 482 PdoExt->Common.State = dsStopped; 483 PdoExt->IsaPnpDevice = IsaDevice; 484 PdoExt->FdoExt = FdoExt; 485 486 Status = IsaFdoCreateDeviceIDs(PdoExt); 487 488 if (NT_SUCCESS(Status)) 489 Status = IsaPnpCreateLogicalDeviceRequirements(PdoExt); 490 491 if (NT_SUCCESS(Status)) 492 Status = IsaPnpCreateLogicalDeviceResources(PdoExt); 493 494 if (!NT_SUCCESS(Status)) 495 { 496 IoDeleteDevice(IsaDevice->Pdo); 497 IsaDevice->Pdo = NULL; 498 break; 499 } 500 } 501 DeviceRelations->Objects[i++] = IsaDevice->Pdo; 502 503 ObReferenceObject(IsaDevice->Pdo); 504 505 CurrentEntry = CurrentEntry->Flink; 506 } 507 508 DeviceRelations->Count = i; 509 510 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; 511 512 return Status; 513 } 514 515 static IO_COMPLETION_ROUTINE ForwardIrpCompletion; 516 517 static 518 NTSTATUS 519 NTAPI 520 ForwardIrpCompletion( 521 IN PDEVICE_OBJECT DeviceObject, 522 IN PIRP Irp, 523 IN PVOID Context) 524 { 525 UNREFERENCED_PARAMETER(DeviceObject); 526 527 if (Irp->PendingReturned) 528 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE); 529 530 return STATUS_MORE_PROCESSING_REQUIRED; 531 } 532 533 NTSTATUS 534 NTAPI 535 IsaForwardIrpSynchronous( 536 IN PISAPNP_FDO_EXTENSION FdoExt, 537 IN PIRP Irp) 538 { 539 KEVENT Event; 540 NTSTATUS Status; 541 542 KeInitializeEvent(&Event, NotificationEvent, FALSE); 543 IoCopyCurrentIrpStackLocationToNext(Irp); 544 545 IoSetCompletionRoutine(Irp, ForwardIrpCompletion, &Event, TRUE, TRUE, TRUE); 546 547 Status = IoCallDriver(FdoExt->Ldo, Irp); 548 if (Status == STATUS_PENDING) 549 { 550 Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL); 551 if (NT_SUCCESS(Status)) 552 Status = Irp->IoStatus.Status; 553 } 554 555 return Status; 556 } 557 558 _Dispatch_type_(IRP_MJ_CREATE) 559 _Dispatch_type_(IRP_MJ_CLOSE) 560 static DRIVER_DISPATCH IsaCreateClose; 561 562 static 563 NTSTATUS 564 NTAPI 565 IsaCreateClose( 566 _In_ PDEVICE_OBJECT DeviceObject, 567 _Inout_ PIRP Irp) 568 { 569 Irp->IoStatus.Status = STATUS_SUCCESS; 570 Irp->IoStatus.Information = FILE_OPENED; 571 572 DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp); 573 574 IoCompleteRequest(Irp, IO_NO_INCREMENT); 575 576 return STATUS_SUCCESS; 577 } 578 579 static DRIVER_DISPATCH IsaIoctl; 580 581 static 582 NTSTATUS 583 NTAPI 584 IsaIoctl( 585 IN PDEVICE_OBJECT DeviceObject, 586 IN PIRP Irp) 587 { 588 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 589 NTSTATUS Status; 590 591 DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp); 592 593 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) 594 { 595 default: 596 DPRINT1("Unknown ioctl code: %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode); 597 Status = STATUS_NOT_SUPPORTED; 598 break; 599 } 600 601 Irp->IoStatus.Status = Status; 602 IoCompleteRequest(Irp, IO_NO_INCREMENT); 603 604 return Status; 605 } 606 607 static DRIVER_DISPATCH IsaReadWrite; 608 609 static 610 NTSTATUS 611 NTAPI 612 IsaReadWrite( 613 IN PDEVICE_OBJECT DeviceObject, 614 IN PIRP Irp) 615 { 616 DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp); 617 618 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 619 Irp->IoStatus.Information = 0; 620 621 IoCompleteRequest(Irp, IO_NO_INCREMENT); 622 623 return STATUS_NOT_SUPPORTED; 624 } 625 626 static 627 NTSTATUS 628 NTAPI 629 IsaPnpCreateReadPortDORequirements( 630 _In_ PISAPNP_PDO_EXTENSION PdoExt) 631 { 632 ULONG ListSize, i; 633 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; 634 PIO_RESOURCE_DESCRIPTOR Descriptor; 635 const ULONG Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS, 636 0x274, 0x3E4, 0x204, 0x2E4, 0x354, 0x2F4 }; 637 638 ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) 639 + 2 * RTL_NUMBER_OF(Ports) * sizeof(IO_RESOURCE_DESCRIPTOR); 640 RequirementsList = ExAllocatePool(PagedPool, ListSize); 641 if (!RequirementsList) 642 return STATUS_NO_MEMORY; 643 644 RtlZeroMemory(RequirementsList, ListSize); 645 RequirementsList->ListSize = ListSize; 646 RequirementsList->AlternativeLists = 1; 647 648 RequirementsList->List[0].Version = 1; 649 RequirementsList->List[0].Revision = 1; 650 RequirementsList->List[0].Count = 2 * RTL_NUMBER_OF(Ports); 651 652 for (i = 0; i < 2 * RTL_NUMBER_OF(Ports); i += 2) 653 { 654 Descriptor = &RequirementsList->List[0].Descriptors[i]; 655 656 /* Expected port */ 657 Descriptor[0].Type = CmResourceTypePort; 658 Descriptor[0].ShareDisposition = CmResourceShareDeviceExclusive; 659 Descriptor[0].Flags = CM_RESOURCE_PORT_16_BIT_DECODE; 660 Descriptor[0].u.Port.Length = Ports[i / 2] & 1 ? 0x01 : 0x04; 661 Descriptor[0].u.Port.Alignment = 0x01; 662 Descriptor[0].u.Port.MinimumAddress.LowPart = Ports[i / 2]; 663 Descriptor[0].u.Port.MaximumAddress.LowPart = Ports[i / 2] + Descriptor[0].u.Port.Length - 1; 664 665 /* ... but mark it as optional */ 666 Descriptor[1].Option = IO_RESOURCE_ALTERNATIVE; 667 Descriptor[1].Type = CmResourceTypePort; 668 Descriptor[1].ShareDisposition = CmResourceShareDeviceExclusive; 669 Descriptor[1].Flags = CM_RESOURCE_PORT_16_BIT_DECODE; 670 Descriptor[1].u.Port.Alignment = 0x01; 671 } 672 673 PdoExt->RequirementsList = RequirementsList; 674 return STATUS_SUCCESS; 675 } 676 677 static 678 NTSTATUS 679 NTAPI 680 IsaPnpCreateReadPortDOResources( 681 _In_ PISAPNP_PDO_EXTENSION PdoExt) 682 { 683 const USHORT Ports[] = { ISAPNP_WRITE_DATA, ISAPNP_ADDRESS }; 684 ULONG ListSize, i; 685 PCM_RESOURCE_LIST ResourceList; 686 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; 687 688 ListSize = sizeof(CM_RESOURCE_LIST) + 689 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (RTL_NUMBER_OF(Ports) - 1); 690 ResourceList = ExAllocatePool(PagedPool, ListSize); 691 if (!ResourceList) 692 return STATUS_NO_MEMORY; 693 694 RtlZeroMemory(ResourceList, ListSize); 695 ResourceList->Count = 1; 696 ResourceList->List[0].InterfaceType = Internal; 697 ResourceList->List[0].PartialResourceList.Version = 1; 698 ResourceList->List[0].PartialResourceList.Revision = 1; 699 ResourceList->List[0].PartialResourceList.Count = RTL_NUMBER_OF(Ports); 700 701 for (i = 0; i < RTL_NUMBER_OF(Ports); i++) 702 { 703 Descriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 704 Descriptor->Type = CmResourceTypePort; 705 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; 706 Descriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE; 707 Descriptor->u.Port.Length = 0x01; 708 Descriptor->u.Port.Start.LowPart = Ports[i]; 709 } 710 711 PdoExt->ResourceList = ResourceList; 712 PdoExt->ResourceListSize = ListSize; 713 return STATUS_SUCCESS; 714 } 715 716 static 717 NTSTATUS 718 NTAPI 719 IsaPnpCreateReadPortDO( 720 _In_ PISAPNP_FDO_EXTENSION FdoExt) 721 { 722 UNICODE_STRING DeviceID = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0"); 723 UNICODE_STRING HardwareIDs = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0\0"); 724 UNICODE_STRING CompatibleIDs = RTL_CONSTANT_STRING(L"\0\0"); 725 UNICODE_STRING InstanceID = RTL_CONSTANT_STRING(L"0\0"); 726 PISAPNP_PDO_EXTENSION PdoExt; 727 NTSTATUS Status; 728 729 Status = IoCreateDevice(FdoExt->DriverObject, 730 sizeof(ISAPNP_PDO_EXTENSION), 731 NULL, 732 FILE_DEVICE_CONTROLLER, 733 FILE_DEVICE_SECURE_OPEN, 734 FALSE, 735 &FdoExt->ReadPortPdo); 736 if (!NT_SUCCESS(Status)) 737 return Status; 738 739 PdoExt = FdoExt->ReadPortPdo->DeviceExtension; 740 RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION)); 741 PdoExt->Common.IsFdo = FALSE; 742 PdoExt->Common.Self = FdoExt->ReadPortPdo; 743 PdoExt->Common.State = dsStopped; 744 PdoExt->FdoExt = FdoExt; 745 746 Status = IsaPnpDuplicateUnicodeString(0, 747 &DeviceID, 748 &PdoExt->DeviceID); 749 if (!NT_SUCCESS(Status)) 750 return Status; 751 752 Status = IsaPnpDuplicateUnicodeString(0, 753 &HardwareIDs, 754 &PdoExt->HardwareIDs); 755 if (!NT_SUCCESS(Status)) 756 return Status; 757 758 Status = IsaPnpDuplicateUnicodeString(0, 759 &CompatibleIDs, 760 &PdoExt->CompatibleIDs); 761 if (!NT_SUCCESS(Status)) 762 return Status; 763 764 Status = IsaPnpDuplicateUnicodeString(0, 765 &InstanceID, 766 &PdoExt->InstanceID); 767 if (!NT_SUCCESS(Status)) 768 return Status; 769 770 Status = IsaPnpCreateReadPortDORequirements(PdoExt); 771 if (!NT_SUCCESS(Status)) 772 return Status; 773 774 Status = IsaPnpCreateReadPortDOResources(PdoExt); 775 if (!NT_SUCCESS(Status)) 776 return Status; 777 778 return Status; 779 } 780 781 static 782 NTSTATUS 783 NTAPI 784 IsaAddDevice( 785 _In_ PDRIVER_OBJECT DriverObject, 786 _In_ PDEVICE_OBJECT PhysicalDeviceObject) 787 { 788 PDEVICE_OBJECT Fdo; 789 PISAPNP_FDO_EXTENSION FdoExt; 790 NTSTATUS Status; 791 792 DPRINT("%s(%p, %p)\n", __FUNCTION__, DriverObject, PhysicalDeviceObject); 793 794 Status = IoCreateDevice(DriverObject, 795 sizeof(*FdoExt), 796 NULL, 797 FILE_DEVICE_BUS_EXTENDER, 798 FILE_DEVICE_SECURE_OPEN, 799 TRUE, 800 &Fdo); 801 if (!NT_SUCCESS(Status)) 802 { 803 DPRINT1("Failed to create FDO (0x%08lx)\n", Status); 804 return Status; 805 } 806 807 FdoExt = Fdo->DeviceExtension; 808 RtlZeroMemory(FdoExt, sizeof(*FdoExt)); 809 810 FdoExt->Common.Self = Fdo; 811 FdoExt->Common.IsFdo = TRUE; 812 FdoExt->Common.State = dsStopped; 813 FdoExt->DriverObject = DriverObject; 814 FdoExt->Pdo = PhysicalDeviceObject; 815 FdoExt->Ldo = IoAttachDeviceToDeviceStack(Fdo, 816 PhysicalDeviceObject); 817 818 InitializeListHead(&FdoExt->DeviceListHead); 819 KeInitializeSpinLock(&FdoExt->Lock); 820 821 Status = IsaPnpCreateReadPortDO(FdoExt); 822 if (!NT_SUCCESS(Status)) 823 return Status; 824 825 Fdo->Flags &= ~DO_DEVICE_INITIALIZING; 826 FdoExt->ReadPortPdo->Flags &= ~DO_DEVICE_INITIALIZING; 827 828 return STATUS_SUCCESS; 829 } 830 831 _Dispatch_type_(IRP_MJ_POWER) 832 DRIVER_DISPATCH IsaPower; 833 834 NTSTATUS 835 NTAPI 836 IsaPower( 837 _In_ PDEVICE_OBJECT DeviceObject, 838 _Inout_ PIRP Irp) 839 { 840 PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension; 841 NTSTATUS Status; 842 843 if (!DevExt->IsFdo) 844 { 845 Status = Irp->IoStatus.Status; 846 IoCompleteRequest(Irp, IO_NO_INCREMENT); 847 return Status; 848 } 849 850 PoStartNextPowerIrp(Irp); 851 IoSkipCurrentIrpStackLocation(Irp); 852 return PoCallDriver(((PISAPNP_FDO_EXTENSION)DevExt)->Ldo, Irp); 853 } 854 855 _Dispatch_type_(IRP_MJ_PNP) 856 static DRIVER_DISPATCH IsaPnp; 857 858 static 859 NTSTATUS 860 NTAPI 861 IsaPnp( 862 _In_ PDEVICE_OBJECT DeviceObject, 863 _Inout_ PIRP Irp) 864 { 865 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 866 PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension; 867 868 DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp); 869 870 if (DevExt->IsFdo) 871 return IsaFdoPnp((PISAPNP_FDO_EXTENSION)DevExt, Irp, IrpSp); 872 else 873 return IsaPdoPnp((PISAPNP_PDO_EXTENSION)DevExt, Irp, IrpSp); 874 } 875 876 NTSTATUS 877 NTAPI 878 DriverEntry( 879 _In_ PDRIVER_OBJECT DriverObject, 880 _In_ PUNICODE_STRING RegistryPath) 881 { 882 DPRINT("%s(%p, %wZ)\n", __FUNCTION__, DriverObject, RegistryPath); 883 884 DriverObject->MajorFunction[IRP_MJ_CREATE] = IsaCreateClose; 885 DriverObject->MajorFunction[IRP_MJ_CLOSE] = IsaCreateClose; 886 DriverObject->MajorFunction[IRP_MJ_READ] = IsaReadWrite; 887 DriverObject->MajorFunction[IRP_MJ_WRITE] = IsaReadWrite; 888 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaIoctl; 889 DriverObject->MajorFunction[IRP_MJ_PNP] = IsaPnp; 890 DriverObject->MajorFunction[IRP_MJ_POWER] = IsaPower; 891 DriverObject->DriverExtension->AddDevice = IsaAddDevice; 892 893 return STATUS_SUCCESS; 894 } 895 896 /* EOF */ 897