1 /* 2 * PROJECT: ReactOS ISA PnP Bus driver 3 * FILE: hardware.c 4 * PURPOSE: Hardware support code 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 static 15 inline 16 VOID 17 WriteAddress( 18 IN USHORT Address) 19 { 20 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_ADDRESS, Address); 21 } 22 23 static 24 inline 25 VOID 26 WriteData( 27 IN USHORT Data) 28 { 29 WRITE_PORT_UCHAR((PUCHAR)ISAPNP_WRITE_DATA, Data); 30 } 31 32 static 33 inline 34 UCHAR 35 ReadData( 36 IN PUCHAR ReadDataPort) 37 { 38 return READ_PORT_UCHAR(ReadDataPort); 39 } 40 41 static 42 inline 43 VOID 44 WriteByte( 45 IN USHORT Address, 46 IN USHORT Value) 47 { 48 WriteAddress(Address); 49 WriteData(Value); 50 } 51 52 static 53 inline 54 UCHAR 55 ReadByte( 56 IN PUCHAR ReadDataPort, 57 IN USHORT Address) 58 { 59 WriteAddress(Address); 60 return ReadData(ReadDataPort); 61 } 62 63 static 64 inline 65 USHORT 66 ReadWord( 67 IN PUCHAR ReadDataPort, 68 IN USHORT Address) 69 { 70 return ((ReadByte(ReadDataPort, Address) << 8) | 71 (ReadByte(ReadDataPort, Address + 1))); 72 } 73 74 static 75 inline 76 VOID 77 SetReadDataPort( 78 IN PUCHAR ReadDataPort) 79 { 80 WriteByte(ISAPNP_READPORT, ((ULONG_PTR)ReadDataPort >> 2)); 81 } 82 83 static 84 inline 85 VOID 86 EnterIsolationState(VOID) 87 { 88 WriteAddress(ISAPNP_SERIALISOLATION); 89 } 90 91 static 92 inline 93 VOID 94 WaitForKey(VOID) 95 { 96 WriteByte(ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY); 97 } 98 99 static 100 inline 101 VOID 102 ResetCsn(VOID) 103 { 104 WriteByte(ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN); 105 } 106 107 static 108 inline 109 VOID 110 Wake( 111 IN USHORT Csn) 112 { 113 WriteByte(ISAPNP_WAKE, Csn); 114 } 115 116 static 117 inline 118 USHORT 119 ReadResourceData( 120 IN PUCHAR ReadDataPort) 121 { 122 return ReadByte(ReadDataPort, ISAPNP_RESOURCEDATA); 123 } 124 125 static 126 inline 127 USHORT 128 ReadStatus( 129 IN PUCHAR ReadDataPort) 130 { 131 return ReadByte(ReadDataPort, ISAPNP_STATUS); 132 } 133 134 static 135 inline 136 VOID 137 WriteCsn( 138 IN USHORT Csn) 139 { 140 WriteByte(ISAPNP_CARDSELECTNUMBER, Csn); 141 } 142 143 static 144 inline 145 VOID 146 WriteLogicalDeviceNumber( 147 IN USHORT LogDev) 148 { 149 WriteByte(ISAPNP_LOGICALDEVICENUMBER, LogDev); 150 } 151 152 static 153 inline 154 VOID 155 ActivateDevice( 156 IN USHORT LogDev) 157 { 158 WriteLogicalDeviceNumber(LogDev); 159 WriteByte(ISAPNP_ACTIVATE, 1); 160 } 161 162 static 163 inline 164 VOID 165 DeactivateDevice( 166 IN USHORT LogDev) 167 { 168 WriteLogicalDeviceNumber(LogDev); 169 WriteByte(ISAPNP_ACTIVATE, 0); 170 } 171 172 static 173 inline 174 USHORT 175 ReadIoBase( 176 IN PUCHAR ReadDataPort, 177 IN USHORT Index) 178 { 179 return ReadWord(ReadDataPort, ISAPNP_IOBASE(Index)); 180 } 181 182 static 183 inline 184 USHORT 185 ReadIrqNo( 186 IN PUCHAR ReadDataPort, 187 IN USHORT Index) 188 { 189 return ReadByte(ReadDataPort, ISAPNP_IRQNO(Index)); 190 } 191 192 static 193 inline 194 USHORT 195 ReadIrqType( 196 IN PUCHAR ReadDataPort, 197 IN USHORT Index) 198 { 199 return ReadByte(ReadDataPort, ISAPNP_IRQTYPE(Index)); 200 } 201 202 static 203 inline 204 USHORT 205 ReadDmaChannel( 206 IN PUCHAR ReadDataPort, 207 IN USHORT Index) 208 { 209 return ReadByte(ReadDataPort, ISAPNP_DMACHANNEL(Index)); 210 } 211 212 static 213 inline 214 VOID 215 HwDelay(VOID) 216 { 217 KeStallExecutionProcessor(1000); 218 } 219 220 static 221 inline 222 UCHAR 223 NextLFSR( 224 IN UCHAR Lfsr, 225 IN UCHAR InputBit) 226 { 227 UCHAR NextLfsr = Lfsr >> 1; 228 229 NextLfsr |= (((Lfsr ^ NextLfsr) ^ InputBit)) << 7; 230 231 return NextLfsr; 232 } 233 234 static 235 VOID 236 SendKey(VOID) 237 { 238 UCHAR i, Lfsr; 239 240 HwDelay(); 241 WriteAddress(0x00); 242 WriteAddress(0x00); 243 244 Lfsr = ISAPNP_LFSR_SEED; 245 for (i = 0; i < 32; i++) 246 { 247 WriteAddress(Lfsr); 248 Lfsr = NextLFSR(Lfsr, 0); 249 } 250 } 251 252 static 253 USHORT 254 PeekByte( 255 IN PUCHAR ReadDataPort) 256 { 257 USHORT i; 258 259 for (i = 0; i < 20; i++) 260 { 261 if (ReadStatus(ReadDataPort) & 0x01) 262 return ReadResourceData(ReadDataPort); 263 264 HwDelay(); 265 } 266 267 return 0xFF; 268 } 269 270 static 271 VOID 272 Peek( 273 IN PUCHAR ReadDataPort, 274 IN OUT PVOID Buffer, 275 IN ULONG Length) 276 { 277 USHORT i, Byte; 278 279 for (i = 0; i < Length; i++) 280 { 281 Byte = PeekByte(ReadDataPort); 282 if (Buffer) 283 *((PUCHAR)Buffer + i) = Byte; 284 } 285 } 286 287 static 288 USHORT 289 IsaPnpChecksum( 290 IN PISAPNP_IDENTIFIER Identifier) 291 { 292 UCHAR i, j, Lfsr, Byte; 293 294 Lfsr = ISAPNP_LFSR_SEED; 295 for (i = 0; i < 8; i++) 296 { 297 Byte = *(((PUCHAR)Identifier) + i); 298 for (j = 0; j < 8; j++) 299 { 300 Lfsr = NextLFSR(Lfsr, Byte); 301 Byte >>= 1; 302 } 303 } 304 305 return Lfsr; 306 } 307 308 static 309 BOOLEAN 310 ReadTags( 311 IN PUCHAR ReadDataPort, 312 IN USHORT LogDev, 313 IN OUT PISAPNP_LOGICAL_DEVICE LogDevice) 314 { 315 BOOLEAN res = FALSE; 316 PVOID Buffer; 317 USHORT Tag, TagLen, MaxLen; 318 ULONG NumberOfIo = 0, NumberOfIrq = 0, NumberOfDma = 0; 319 320 LogDev += 1; 321 322 while (TRUE) 323 { 324 Tag = PeekByte(ReadDataPort); 325 if (ISAPNP_IS_SMALL_TAG(Tag)) 326 { 327 TagLen = ISAPNP_SMALL_TAG_LEN(Tag); 328 Tag = ISAPNP_SMALL_TAG_NAME(Tag); 329 } 330 else 331 { 332 TagLen = PeekByte(ReadDataPort) + (PeekByte(ReadDataPort) << 8); 333 Tag = ISAPNP_LARGE_TAG_NAME(Tag); 334 } 335 if (Tag == ISAPNP_TAG_END) 336 break; 337 338 Buffer = NULL; 339 if (Tag == ISAPNP_TAG_LOGDEVID) 340 { 341 MaxLen = sizeof(LogDevice->LogDevId); 342 Buffer = &LogDevice->LogDevId; 343 LogDev--; 344 } 345 else if (Tag == ISAPNP_TAG_IRQ && NumberOfIrq < ARRAYSIZE(LogDevice->Irq)) 346 { 347 MaxLen = sizeof(LogDevice->Irq[NumberOfIrq].Description); 348 Buffer = &LogDevice->Irq[NumberOfIrq].Description; 349 NumberOfIrq++; 350 } 351 else if (Tag == ISAPNP_TAG_IOPORT && NumberOfIo < ARRAYSIZE(LogDevice->Io)) 352 { 353 MaxLen = sizeof(LogDevice->Io[NumberOfIo].Description); 354 Buffer = &LogDevice->Io[NumberOfIo].Description; 355 NumberOfIo++; 356 } 357 else if (Tag == ISAPNP_TAG_DMA && NumberOfDma < ARRAYSIZE(LogDevice->Dma)) 358 { 359 MaxLen = sizeof(LogDevice->Dma[NumberOfDma].Description); 360 Buffer = &LogDevice->Dma[NumberOfDma].Description; 361 NumberOfDma++; 362 } 363 else if (LogDev == 0) 364 { 365 DPRINT1("Found unknown tag 0x%x (len %d)\n", Tag, TagLen); 366 } 367 368 if (Buffer && LogDev == 0) 369 { 370 res = TRUE; 371 if (MaxLen > TagLen) 372 { 373 Peek(ReadDataPort, Buffer, TagLen); 374 } 375 else 376 { 377 Peek(ReadDataPort, Buffer, MaxLen); 378 Peek(ReadDataPort, NULL, TagLen - MaxLen); 379 } 380 } 381 else 382 { 383 /* We don't want to read informations on this 384 * logical device, or we don't know the tag. */ 385 Peek(ReadDataPort, NULL, TagLen); 386 } 387 }; 388 389 return res; 390 } 391 392 static 393 INT 394 TryIsolate( 395 IN PUCHAR ReadDataPort) 396 { 397 ISAPNP_IDENTIFIER Identifier; 398 USHORT i, j; 399 BOOLEAN Seen55aa, SeenLife; 400 INT Csn = 0; 401 USHORT Byte, Data; 402 403 DPRINT("Setting read data port: 0x%p\n", ReadDataPort); 404 405 WaitForKey(); 406 SendKey(); 407 408 ResetCsn(); 409 HwDelay(); 410 HwDelay(); 411 412 WaitForKey(); 413 SendKey(); 414 Wake(0x00); 415 416 SetReadDataPort(ReadDataPort); 417 HwDelay(); 418 419 while (TRUE) 420 { 421 EnterIsolationState(); 422 HwDelay(); 423 424 RtlZeroMemory(&Identifier, sizeof(Identifier)); 425 426 Seen55aa = SeenLife = FALSE; 427 for (i = 0; i < 9; i++) 428 { 429 Byte = 0; 430 for (j = 0; j < 8; j++) 431 { 432 Data = ReadData(ReadDataPort); 433 HwDelay(); 434 Data = ((Data << 8) | ReadData(ReadDataPort)); 435 HwDelay(); 436 Byte >>= 1; 437 438 if (Data != 0xFFFF) 439 { 440 SeenLife = TRUE; 441 if (Data == 0x55AA) 442 { 443 Byte |= 0x80; 444 Seen55aa = TRUE; 445 } 446 } 447 } 448 *(((PUCHAR)&Identifier) + i) = Byte; 449 } 450 451 if (!Seen55aa) 452 { 453 if (Csn) 454 { 455 DPRINT("Found no more cards\n"); 456 } 457 else 458 { 459 if (SeenLife) 460 { 461 DPRINT("Saw life but no cards, trying new read port\n"); 462 Csn = -1; 463 } 464 else 465 { 466 DPRINT("Saw no sign of life, abandoning isolation\n"); 467 } 468 } 469 break; 470 } 471 472 if (Identifier.Checksum != IsaPnpChecksum(&Identifier)) 473 { 474 DPRINT("Bad checksum, trying next read data port\n"); 475 Csn = -1; 476 break; 477 } 478 479 Csn++; 480 481 WriteCsn(Csn); 482 HwDelay(); 483 484 Wake(0x00); 485 HwDelay(); 486 } 487 488 WaitForKey(); 489 490 if (Csn > 0) 491 { 492 DPRINT("Found %d cards at read port 0x%p\n", Csn, ReadDataPort); 493 } 494 495 return Csn; 496 } 497 498 VOID 499 DeviceActivation( 500 IN PISAPNP_LOGICAL_DEVICE IsaDevice, 501 IN BOOLEAN Activate) 502 { 503 WaitForKey(); 504 SendKey(); 505 Wake(IsaDevice->CSN); 506 507 if (Activate) 508 ActivateDevice(IsaDevice->LDN); 509 else 510 DeactivateDevice(IsaDevice->LDN); 511 512 HwDelay(); 513 514 WaitForKey(); 515 } 516 517 NTSTATUS 518 ProbeIsaPnpBus( 519 IN PISAPNP_FDO_EXTENSION FdoExt) 520 { 521 PISAPNP_LOGICAL_DEVICE LogDevice; 522 ISAPNP_IDENTIFIER Identifier; 523 USHORT Csn; 524 USHORT LogDev; 525 ULONG i; 526 527 ASSERT(FdoExt->ReadDataPort); 528 529 for (Csn = 1; Csn <= 0xFF; Csn++) 530 { 531 for (LogDev = 0; LogDev <= 0xFF; LogDev++) 532 { 533 LogDevice = ExAllocatePool(NonPagedPool, sizeof(ISAPNP_LOGICAL_DEVICE)); 534 if (!LogDevice) 535 return STATUS_NO_MEMORY; 536 537 RtlZeroMemory(LogDevice, sizeof(ISAPNP_LOGICAL_DEVICE)); 538 539 LogDevice->CSN = Csn; 540 LogDevice->LDN = LogDev; 541 542 WaitForKey(); 543 SendKey(); 544 Wake(Csn); 545 546 Peek(FdoExt->ReadDataPort, &Identifier, sizeof(Identifier)); 547 548 if (Identifier.VendorId & 0x80) 549 { 550 ExFreePool(LogDevice); 551 return STATUS_SUCCESS; 552 } 553 554 if (!ReadTags(FdoExt->ReadDataPort, LogDev, LogDevice)) 555 break; 556 557 WriteLogicalDeviceNumber(LogDev); 558 559 LogDevice->VendorId[0] = ((LogDevice->LogDevId.VendorId >> 2) & 0x1f) + 'A' - 1, 560 LogDevice->VendorId[1] = (((LogDevice->LogDevId.VendorId & 0x3) << 3) | ((LogDevice->LogDevId.VendorId >> 13) & 0x7)) + 'A' - 1, 561 LogDevice->VendorId[2] = ((LogDevice->LogDevId.VendorId >> 8) & 0x1f) + 'A' - 1, 562 LogDevice->ProdId = RtlUshortByteSwap(LogDevice->LogDevId.ProdId); 563 LogDevice->SerialNumber = Identifier.Serial; 564 for (i = 0; i < ARRAYSIZE(LogDevice->Io); i++) 565 LogDevice->Io[i].CurrentBase = ReadIoBase(FdoExt->ReadDataPort, i); 566 for (i = 0; i < ARRAYSIZE(LogDevice->Irq); i++) 567 { 568 LogDevice->Irq[i].CurrentNo = ReadIrqNo(FdoExt->ReadDataPort, i); 569 LogDevice->Irq[i].CurrentType = ReadIrqType(FdoExt->ReadDataPort, i); 570 } 571 for (i = 0; i < ARRAYSIZE(LogDevice->Dma); i++) 572 { 573 LogDevice->Dma[i].CurrentChannel = ReadDmaChannel(FdoExt->ReadDataPort, i); 574 } 575 576 DPRINT1("Detected ISA PnP device - VID: '%3s' PID: 0x%x SN: 0x%08x IoBase: 0x%x IRQ:0x%x\n", 577 LogDevice->VendorId, LogDevice->ProdId, LogDevice->SerialNumber, LogDevice->Io[0].CurrentBase, LogDevice->Irq[0].CurrentNo); 578 579 WaitForKey(); 580 581 InsertTailList(&FdoExt->DeviceListHead, &LogDevice->ListEntry); 582 FdoExt->DeviceCount++; 583 } 584 } 585 586 return STATUS_SUCCESS; 587 } 588 589 NTSTATUS 590 NTAPI 591 IsaHwTryReadDataPort( 592 IN PUCHAR ReadDataPort) 593 { 594 return TryIsolate(ReadDataPort) > 0 ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; 595 } 596 597 NTSTATUS 598 NTAPI 599 IsaHwActivateDevice( 600 IN PISAPNP_LOGICAL_DEVICE LogicalDevice) 601 { 602 DeviceActivation(LogicalDevice, 603 TRUE); 604 605 return STATUS_SUCCESS; 606 } 607 608 NTSTATUS 609 NTAPI 610 IsaHwDeactivateDevice( 611 IN PISAPNP_LOGICAL_DEVICE LogicalDevice) 612 { 613 DeviceActivation(LogicalDevice, 614 FALSE); 615 616 return STATUS_SUCCESS; 617 } 618 619 NTSTATUS 620 NTAPI 621 IsaHwFillDeviceList( 622 IN PISAPNP_FDO_EXTENSION FdoExt) 623 { 624 return ProbeIsaPnpBus(FdoExt); 625 } 626