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