1 /* 2 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: drivers/input/i8042prt/pnp.c 5 * PURPOSE: IRP_MJ_PNP operations 6 * PROGRAMMERS: Copyright 2006-2007 Herv� Poussineau (hpoussin@reactos.org) 7 * Copyright 2008 Colin Finck (mail@colinfinck.de) 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include "i8042prt.h" 13 14 /* FUNCTIONS *****************************************************************/ 15 16 /* This is all pretty confusing. There's more than one way to 17 * disable/enable the keyboard. You can send KBD_ENABLE to the 18 * keyboard, and it will start scanning keys. Sending KBD_DISABLE 19 * will disable the key scanning but also reset the parameters to 20 * defaults. 21 * 22 * You can also send 0xAE to the controller for enabling the 23 * keyboard clock line and 0xAD for disabling it. Then it'll 24 * automatically get turned on at the next command. The last 25 * way is by modifying the bit that drives the clock line in the 26 * 'command byte' of the controller. This is almost, but not quite, 27 * the same as the AE/AD thing. The difference can be used to detect 28 * some really old broken keyboard controllers which I hope won't be 29 * necessary. 30 * 31 * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse 32 * some kvm switches. 33 */ 34 BOOLEAN 35 i8042ChangeMode( 36 IN PPORT_DEVICE_EXTENSION DeviceExtension, 37 IN UCHAR FlagsToDisable, 38 IN UCHAR FlagsToEnable) 39 { 40 UCHAR Value; 41 NTSTATUS Status; 42 43 if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_READ_MODE)) 44 { 45 WARN_(I8042PRT, "Can't read i8042 mode\n"); 46 return FALSE; 47 } 48 49 Status = i8042ReadDataWait(DeviceExtension, &Value); 50 if (!NT_SUCCESS(Status)) 51 { 52 WARN_(I8042PRT, "No response after read i8042 mode\n"); 53 return FALSE; 54 } 55 56 Value &= ~FlagsToDisable; 57 Value |= FlagsToEnable; 58 59 if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_WRITE_MODE)) 60 { 61 WARN_(I8042PRT, "Can't set i8042 mode\n"); 62 return FALSE; 63 } 64 65 if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value)) 66 { 67 WARN_(I8042PRT, "Can't send i8042 mode\n"); 68 return FALSE; 69 } 70 71 return TRUE; 72 } 73 74 static NTSTATUS 75 i8042BasicDetect( 76 IN PPORT_DEVICE_EXTENSION DeviceExtension) 77 { 78 NTSTATUS Status; 79 ULONG ResendIterations; 80 UCHAR Value = 0; 81 82 /* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */ 83 if (!i8042ChangeMode(DeviceExtension, CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB, CCB_KBD_DISAB | CCB_MOUSE_DISAB)) 84 return STATUS_IO_DEVICE_ERROR; 85 86 i8042Flush(DeviceExtension); 87 88 ResendIterations = DeviceExtension->Settings.ResendIterations + 1; 89 while (ResendIterations--) 90 { 91 if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST)) 92 { 93 WARN_(I8042PRT, "Writing CTRL_SELF_TEST command failed\n"); 94 return STATUS_IO_TIMEOUT; 95 } 96 97 Status = i8042ReadDataWait(DeviceExtension, &Value); 98 if (!NT_SUCCESS(Status)) 99 { 100 WARN_(I8042PRT, "Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status); 101 return Status; 102 } 103 104 if (Value == KBD_SELF_TEST_OK) 105 { 106 INFO_(I8042PRT, "CTRL_SELF_TEST completed successfully!\n"); 107 break; 108 } 109 else if (Value == KBD_RESEND) 110 { 111 TRACE_(I8042PRT, "Resending...\n", Value); 112 KeStallExecutionProcessor(50); 113 } 114 else 115 { 116 WARN_(I8042PRT, "Got 0x%02x instead of 0x55\n", Value); 117 return STATUS_IO_DEVICE_ERROR; 118 } 119 } 120 121 /* 122 * We used to send a KBD_LINE_TEST (0xAB) command here, but on at least HP 123 * Pavilion notebooks the response to that command was incorrect. 124 * So now we just assume that a keyboard is attached. 125 */ 126 DeviceExtension->Flags |= KEYBOARD_PRESENT; 127 128 if (i8042Write(DeviceExtension, DeviceExtension->ControlPort, MOUSE_LINE_TEST)) 129 { 130 Status = i8042ReadDataWait(DeviceExtension, &Value); 131 if (NT_SUCCESS(Status) && Value == 0) 132 DeviceExtension->Flags |= MOUSE_PRESENT; 133 } 134 135 if (IsFirstStageSetup()) 136 /* Ignore the mouse */ 137 DeviceExtension->Flags &= ~MOUSE_PRESENT; 138 139 return STATUS_SUCCESS; 140 } 141 142 static VOID 143 i8042DetectKeyboard( 144 IN PPORT_DEVICE_EXTENSION DeviceExtension) 145 { 146 NTSTATUS Status; 147 148 /* Set LEDs (that is not fatal if some error occurs) */ 149 Status = i8042SynchWritePort(DeviceExtension, 0, KBD_CMD_SET_LEDS, TRUE); 150 if (NT_SUCCESS(Status)) 151 { 152 Status = i8042SynchWritePort(DeviceExtension, 0, 0, TRUE); 153 if (!NT_SUCCESS(Status)) 154 { 155 WARN_(I8042PRT, "Can't finish SET_LEDS (0x%08lx)\n", Status); 156 return; 157 } 158 } 159 else 160 { 161 WARN_(I8042PRT, "Warning: can't write SET_LEDS (0x%08lx)\n", Status); 162 } 163 164 /* Turn on translation and SF (Some machines don't reboot if SF is not set, see ReactOS bug #1842) */ 165 if (!i8042ChangeMode(DeviceExtension, 0, CCB_TRANSLATE | CCB_SYSTEM_FLAG)) 166 return; 167 168 INFO_(I8042PRT, "Keyboard detected\n"); 169 } 170 171 static VOID 172 i8042DetectMouse( 173 IN PPORT_DEVICE_EXTENSION DeviceExtension) 174 { 175 NTSTATUS Status; 176 UCHAR Value; 177 UCHAR ExpectedReply[] = { MOUSE_ACK, 0xAA }; 178 UCHAR ReplyByte; 179 180 i8042Flush(DeviceExtension); 181 182 if(!i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE)) 183 { 184 WARN_(I8042PRT, "Failed to write reset command to mouse\n"); 185 goto failure; 186 } 187 188 /* The implementation of the "Mouse Reset" command differs much from chip to chip. 189 190 By default, the first byte is an ACK, when the mouse is plugged in and working and NACK when it's not. 191 On success, the next bytes are 0xAA and 0x00. 192 193 But on some systems (like ECS K7S5A Pro, SiS 735 chipset), we always get an ACK and 0xAA. 194 Only the last byte indicates, whether a mouse is plugged in. 195 It is either sent or not, so there is no byte, which indicates a failure here. 196 197 After the Mouse Reset command was issued, it usually takes some time until we get a response. 198 So get the first two bytes in a loop. */ 199 for (ReplyByte = 0; 200 ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]); 201 ReplyByte++) 202 { 203 ULONG Counter = 500; 204 205 do 206 { 207 Status = i8042ReadDataWait(DeviceExtension, &Value); 208 209 if(!NT_SUCCESS(Status)) 210 { 211 /* Wait some time before trying again */ 212 KeStallExecutionProcessor(50); 213 } 214 } while (Status == STATUS_IO_TIMEOUT && Counter--); 215 216 if (!NT_SUCCESS(Status)) 217 { 218 WARN_(I8042PRT, "No ACK after mouse reset, status 0x%08lx\n", Status); 219 goto failure; 220 } 221 else if (Value != ExpectedReply[ReplyByte]) 222 { 223 WARN_(I8042PRT, "Unexpected reply: 0x%02x (expected 0x%02x)\n", Value, ExpectedReply[ReplyByte]); 224 goto failure; 225 } 226 } 227 228 /* Finally get the third byte, but only try it one time (see above). 229 Otherwise this takes around 45 seconds on a K7S5A Pro, when no mouse is plugged in. */ 230 Status = i8042ReadDataWait(DeviceExtension, &Value); 231 232 if(!NT_SUCCESS(Status)) 233 { 234 WARN_(I8042PRT, "Last byte was not transmitted after mouse reset, status 0x%08lx\n", Status); 235 goto failure; 236 } 237 else if(Value != 0x00) 238 { 239 WARN_(I8042PRT, "Last byte after mouse reset was not 0x00, but 0x%02x\n", Value); 240 goto failure; 241 } 242 243 INFO_(I8042PRT, "Mouse detected\n"); 244 return; 245 246 failure: 247 /* There is probably no mouse present. On some systems, 248 the probe locks the entire keyboard controller. Let's 249 try to get access to the keyboard again by sending a 250 reset */ 251 i8042Flush(DeviceExtension); 252 i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST); 253 i8042ReadDataWait(DeviceExtension, &Value); 254 i8042Flush(DeviceExtension); 255 256 INFO_(I8042PRT, "Mouse not detected\n"); 257 } 258 259 static NTSTATUS 260 i8042ConnectKeyboardInterrupt( 261 IN PI8042_KEYBOARD_EXTENSION DeviceExtension) 262 { 263 PPORT_DEVICE_EXTENSION PortDeviceExtension; 264 KIRQL DirqlMax; 265 NTSTATUS Status; 266 267 TRACE_(I8042PRT, "i8042ConnectKeyboardInterrupt()\n"); 268 269 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 270 DirqlMax = MAX( 271 PortDeviceExtension->KeyboardInterrupt.Dirql, 272 PortDeviceExtension->MouseInterrupt.Dirql); 273 274 INFO_(I8042PRT, "KeyboardInterrupt.Vector %lu\n", 275 PortDeviceExtension->KeyboardInterrupt.Vector); 276 INFO_(I8042PRT, "KeyboardInterrupt.Dirql %lu\n", 277 PortDeviceExtension->KeyboardInterrupt.Dirql); 278 INFO_(I8042PRT, "KeyboardInterrupt.DirqlMax %lu\n", 279 DirqlMax); 280 INFO_(I8042PRT, "KeyboardInterrupt.InterruptMode %s\n", 281 PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched"); 282 INFO_(I8042PRT, "KeyboardInterrupt.ShareInterrupt %s\n", 283 PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no"); 284 INFO_(I8042PRT, "KeyboardInterrupt.Affinity 0x%lx\n", 285 PortDeviceExtension->KeyboardInterrupt.Affinity); 286 Status = IoConnectInterrupt( 287 &PortDeviceExtension->KeyboardInterrupt.Object, 288 i8042KbdInterruptService, 289 DeviceExtension, &PortDeviceExtension->SpinLock, 290 PortDeviceExtension->KeyboardInterrupt.Vector, PortDeviceExtension->KeyboardInterrupt.Dirql, DirqlMax, 291 PortDeviceExtension->KeyboardInterrupt.InterruptMode, PortDeviceExtension->KeyboardInterrupt.ShareInterrupt, 292 PortDeviceExtension->KeyboardInterrupt.Affinity, FALSE); 293 if (!NT_SUCCESS(Status)) 294 { 295 WARN_(I8042PRT, "IoConnectInterrupt() failed with status 0x%08x\n", Status); 296 return Status; 297 } 298 299 if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql) 300 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object; 301 PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED; 302 return STATUS_SUCCESS; 303 } 304 305 static NTSTATUS 306 i8042ConnectMouseInterrupt( 307 IN PI8042_MOUSE_EXTENSION DeviceExtension) 308 { 309 PPORT_DEVICE_EXTENSION PortDeviceExtension; 310 KIRQL DirqlMax; 311 NTSTATUS Status; 312 313 TRACE_(I8042PRT, "i8042ConnectMouseInterrupt()\n"); 314 315 Status = i8042MouInitialize(DeviceExtension); 316 if (!NT_SUCCESS(Status)) 317 return Status; 318 319 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 320 DirqlMax = MAX( 321 PortDeviceExtension->KeyboardInterrupt.Dirql, 322 PortDeviceExtension->MouseInterrupt.Dirql); 323 324 INFO_(I8042PRT, "MouseInterrupt.Vector %lu\n", 325 PortDeviceExtension->MouseInterrupt.Vector); 326 INFO_(I8042PRT, "MouseInterrupt.Dirql %lu\n", 327 PortDeviceExtension->MouseInterrupt.Dirql); 328 INFO_(I8042PRT, "MouseInterrupt.DirqlMax %lu\n", 329 DirqlMax); 330 INFO_(I8042PRT, "MouseInterrupt.InterruptMode %s\n", 331 PortDeviceExtension->MouseInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched"); 332 INFO_(I8042PRT, "MouseInterrupt.ShareInterrupt %s\n", 333 PortDeviceExtension->MouseInterrupt.ShareInterrupt ? "yes" : "no"); 334 INFO_(I8042PRT, "MouseInterrupt.Affinity 0x%lx\n", 335 PortDeviceExtension->MouseInterrupt.Affinity); 336 Status = IoConnectInterrupt( 337 &PortDeviceExtension->MouseInterrupt.Object, 338 i8042MouInterruptService, 339 DeviceExtension, &PortDeviceExtension->SpinLock, 340 PortDeviceExtension->MouseInterrupt.Vector, PortDeviceExtension->MouseInterrupt.Dirql, DirqlMax, 341 PortDeviceExtension->MouseInterrupt.InterruptMode, PortDeviceExtension->MouseInterrupt.ShareInterrupt, 342 PortDeviceExtension->MouseInterrupt.Affinity, FALSE); 343 if (!NT_SUCCESS(Status)) 344 { 345 WARN_(I8042PRT, "IoConnectInterrupt() failed with status 0x%08x\n", Status); 346 goto cleanup; 347 } 348 349 if (DirqlMax == PortDeviceExtension->MouseInterrupt.Dirql) 350 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->MouseInterrupt.Object; 351 352 PortDeviceExtension->Flags |= MOUSE_INITIALIZED; 353 Status = STATUS_SUCCESS; 354 355 cleanup: 356 if (!NT_SUCCESS(Status)) 357 { 358 PortDeviceExtension->Flags &= ~MOUSE_INITIALIZED; 359 if (PortDeviceExtension->MouseInterrupt.Object) 360 { 361 IoDisconnectInterrupt(PortDeviceExtension->MouseInterrupt.Object); 362 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object; 363 } 364 } 365 return Status; 366 } 367 368 static NTSTATUS 369 EnableInterrupts( 370 IN PPORT_DEVICE_EXTENSION DeviceExtension, 371 IN UCHAR FlagsToDisable, 372 IN UCHAR FlagsToEnable) 373 { 374 i8042Flush(DeviceExtension); 375 376 if (!i8042ChangeMode(DeviceExtension, FlagsToDisable, FlagsToEnable)) 377 return STATUS_UNSUCCESSFUL; 378 379 /* Reset the mouse (if any) to start the detection */ 380 if (DeviceExtension->Flags & MOUSE_PRESENT) 381 { 382 KIRQL Irql; 383 384 Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt); 385 i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE); 386 KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql); 387 } 388 389 return STATUS_SUCCESS; 390 } 391 392 static NTSTATUS 393 StartProcedure( 394 IN PPORT_DEVICE_EXTENSION DeviceExtension) 395 { 396 NTSTATUS Status; 397 UCHAR FlagsToDisable = 0; 398 UCHAR FlagsToEnable = 0; 399 400 if (DeviceExtension->DataPort == 0) 401 { 402 /* Unable to do something at the moment */ 403 return STATUS_SUCCESS; 404 } 405 406 if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT))) 407 { 408 /* Try to detect them */ 409 TRACE_(I8042PRT, "Check if the controller is really a i8042\n"); 410 Status = i8042BasicDetect(DeviceExtension); 411 if (!NT_SUCCESS(Status)) 412 { 413 WARN_(I8042PRT, "i8042BasicDetect() failed with status 0x%08lx\n", Status); 414 return STATUS_UNSUCCESSFUL; 415 } 416 417 /* First detect the mouse and then the keyboard! 418 If we do it the other way round, some systems throw away settings like the keyboard translation, when detecting the mouse. */ 419 TRACE_(I8042PRT, "Detecting mouse\n"); 420 i8042DetectMouse(DeviceExtension); 421 422 TRACE_(I8042PRT, "Detecting keyboard\n"); 423 i8042DetectKeyboard(DeviceExtension); 424 425 INFO_(I8042PRT, "Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO"); 426 INFO_(I8042PRT, "Mouse present : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO"); 427 } 428 429 /* Connect interrupts */ 430 if (DeviceExtension->Flags & KEYBOARD_PRESENT && 431 DeviceExtension->Flags & KEYBOARD_CONNECTED && 432 DeviceExtension->Flags & KEYBOARD_STARTED && 433 !(DeviceExtension->Flags & KEYBOARD_INITIALIZED)) 434 { 435 /* Keyboard is ready to be initialized */ 436 Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension); 437 if (NT_SUCCESS(Status)) 438 { 439 DeviceExtension->Flags |= KEYBOARD_INITIALIZED; 440 FlagsToDisable |= CCB_KBD_DISAB; 441 FlagsToEnable |= CCB_KBD_INT_ENAB; 442 } 443 } 444 445 if (DeviceExtension->Flags & MOUSE_PRESENT && 446 DeviceExtension->Flags & MOUSE_CONNECTED && 447 DeviceExtension->Flags & MOUSE_STARTED && 448 !(DeviceExtension->Flags & MOUSE_INITIALIZED)) 449 { 450 /* Mouse is ready to be initialized */ 451 Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension); 452 if (NT_SUCCESS(Status)) 453 { 454 DeviceExtension->Flags |= MOUSE_INITIALIZED; 455 FlagsToDisable |= CCB_MOUSE_DISAB; 456 FlagsToEnable |= CCB_MOUSE_INT_ENAB; 457 } 458 } 459 460 if (FlagsToEnable) 461 Status = EnableInterrupts(DeviceExtension, FlagsToDisable, FlagsToEnable); 462 else 463 Status = STATUS_SUCCESS; 464 465 return Status; 466 } 467 468 static NTSTATUS 469 i8042PnpStartDevice( 470 IN PDEVICE_OBJECT DeviceObject, 471 IN PCM_RESOURCE_LIST AllocatedResources, 472 IN PCM_RESOURCE_LIST AllocatedResourcesTranslated) 473 { 474 PFDO_DEVICE_EXTENSION DeviceExtension; 475 PPORT_DEVICE_EXTENSION PortDeviceExtension; 476 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor, ResourceDescriptorTranslated; 477 INTERRUPT_DATA InterruptData; 478 BOOLEAN FoundDataPort = FALSE; 479 BOOLEAN FoundControlPort = FALSE; 480 BOOLEAN FoundIrq = FALSE; 481 ULONG i; 482 NTSTATUS Status; 483 484 TRACE_(I8042PRT, "i8042PnpStartDevice(%p)\n", DeviceObject); 485 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 486 PortDeviceExtension = DeviceExtension->PortDeviceExtension; 487 488 ASSERT(DeviceExtension->PnpState == dsStopped); 489 490 if (!AllocatedResources) 491 { 492 WARN_(I8042PRT, "No allocated resources sent to driver\n"); 493 return STATUS_INSUFFICIENT_RESOURCES; 494 } 495 if (AllocatedResources->Count != 1) 496 { 497 WARN_(I8042PRT, "Wrong number of allocated resources sent to driver\n"); 498 return STATUS_INSUFFICIENT_RESOURCES; 499 } 500 if (AllocatedResources->List[0].PartialResourceList.Version != 1 501 || AllocatedResources->List[0].PartialResourceList.Revision != 1 502 || AllocatedResourcesTranslated->List[0].PartialResourceList.Version != 1 503 || AllocatedResourcesTranslated->List[0].PartialResourceList.Revision != 1) 504 { 505 WARN_(I8042PRT, "Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n", 506 AllocatedResources->List[0].PartialResourceList.Version, 507 AllocatedResources->List[0].PartialResourceList.Revision, 508 AllocatedResourcesTranslated->List[0].PartialResourceList.Version, 509 AllocatedResourcesTranslated->List[0].PartialResourceList.Revision); 510 return STATUS_REVISION_MISMATCH; 511 } 512 513 /* Get Irq and optionally control port and data port */ 514 for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++) 515 { 516 ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i]; 517 ResourceDescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i]; 518 switch (ResourceDescriptor->Type) 519 { 520 case CmResourceTypePort: 521 { 522 if (ResourceDescriptor->u.Port.Length == 1) 523 { 524 /* We assume that the first ressource will 525 * be the control port and the second one 526 * will be the data port... 527 */ 528 if (!FoundDataPort) 529 { 530 PortDeviceExtension->DataPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart); 531 INFO_(I8042PRT, "Found data port: %p\n", PortDeviceExtension->DataPort); 532 FoundDataPort = TRUE; 533 } 534 else if (!FoundControlPort) 535 { 536 PortDeviceExtension->ControlPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart); 537 INFO_(I8042PRT, "Found control port: %p\n", PortDeviceExtension->ControlPort); 538 FoundControlPort = TRUE; 539 } 540 else 541 { 542 WARN_(I8042PRT, "Too much I/O ranges provided: 0x%lx\n", ResourceDescriptor->u.Port.Length); 543 return STATUS_INVALID_PARAMETER; 544 } 545 } 546 else 547 WARN_(I8042PRT, "Invalid I/O range length: 0x%lx\n", ResourceDescriptor->u.Port.Length); 548 break; 549 } 550 case CmResourceTypeInterrupt: 551 { 552 if (FoundIrq) 553 return STATUS_INVALID_PARAMETER; 554 InterruptData.Dirql = (KIRQL)ResourceDescriptorTranslated->u.Interrupt.Level; 555 InterruptData.Vector = ResourceDescriptorTranslated->u.Interrupt.Vector; 556 InterruptData.Affinity = ResourceDescriptorTranslated->u.Interrupt.Affinity; 557 if (ResourceDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) 558 InterruptData.InterruptMode = Latched; 559 else 560 InterruptData.InterruptMode = LevelSensitive; 561 InterruptData.ShareInterrupt = (ResourceDescriptorTranslated->ShareDisposition == CmResourceShareShared); 562 INFO_(I8042PRT, "Found irq resource: %lu\n", ResourceDescriptor->u.Interrupt.Level); 563 FoundIrq = TRUE; 564 break; 565 } 566 default: 567 WARN_(I8042PRT, "Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type); 568 } 569 } 570 571 if (!FoundIrq) 572 { 573 WARN_(I8042PRT, "Interrupt resource was not found in allocated resources list\n"); 574 return STATUS_INSUFFICIENT_RESOURCES; 575 } 576 else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort)) 577 { 578 WARN_(I8042PRT, "Some required resources were not found in allocated resources list\n"); 579 return STATUS_INSUFFICIENT_RESOURCES; 580 } 581 else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort)) 582 { 583 WARN_(I8042PRT, "Too much resources were provided in allocated resources list\n"); 584 return STATUS_INVALID_PARAMETER; 585 } 586 587 switch (DeviceExtension->Type) 588 { 589 case Keyboard: 590 { 591 RtlCopyMemory( 592 &PortDeviceExtension->KeyboardInterrupt, 593 &InterruptData, 594 sizeof(INTERRUPT_DATA)); 595 PortDeviceExtension->Flags |= KEYBOARD_STARTED; 596 Status = StartProcedure(PortDeviceExtension); 597 break; 598 } 599 case Mouse: 600 { 601 RtlCopyMemory( 602 &PortDeviceExtension->MouseInterrupt, 603 &InterruptData, 604 sizeof(INTERRUPT_DATA)); 605 PortDeviceExtension->Flags |= MOUSE_STARTED; 606 Status = StartProcedure(PortDeviceExtension); 607 break; 608 } 609 default: 610 { 611 ERR_(I8042PRT, "Unknown FDO type %u\n", DeviceExtension->Type); 612 ASSERT(FALSE); 613 Status = STATUS_INVALID_DEVICE_REQUEST; 614 } 615 } 616 617 if (NT_SUCCESS(Status)) 618 DeviceExtension->PnpState = dsStarted; 619 620 return Status; 621 } 622 623 NTSTATUS NTAPI 624 i8042Pnp( 625 IN PDEVICE_OBJECT DeviceObject, 626 IN PIRP Irp) 627 { 628 PIO_STACK_LOCATION Stack; 629 ULONG MinorFunction; 630 I8042_DEVICE_TYPE DeviceType; 631 ULONG_PTR Information = 0; 632 NTSTATUS Status; 633 634 Stack = IoGetCurrentIrpStackLocation(Irp); 635 MinorFunction = Stack->MinorFunction; 636 DeviceType = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type; 637 638 switch (MinorFunction) 639 { 640 case IRP_MN_START_DEVICE: /* 0x00 */ 641 { 642 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 643 644 /* Call lower driver (if any) */ 645 if (DeviceType != PhysicalDeviceObject) 646 { 647 Status = ForwardIrpAndWait(DeviceObject, Irp); 648 if (NT_SUCCESS(Status)) 649 Status = i8042PnpStartDevice( 650 DeviceObject, 651 Stack->Parameters.StartDevice.AllocatedResources, 652 Stack->Parameters.StartDevice.AllocatedResourcesTranslated); 653 } 654 else 655 Status = STATUS_SUCCESS; 656 break; 657 } 658 case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x07 */ 659 { 660 switch (Stack->Parameters.QueryDeviceRelations.Type) 661 { 662 case BusRelations: 663 { 664 PDEVICE_RELATIONS DeviceRelations; 665 666 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); 667 DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), I8042PRT_TAG); 668 if (DeviceRelations) 669 { 670 DeviceRelations->Count = 0; 671 Information = (ULONG_PTR)DeviceRelations; 672 Status = STATUS_SUCCESS; 673 } 674 else 675 Status = STATUS_INSUFFICIENT_RESOURCES; 676 break; 677 } 678 case RemovalRelations: 679 { 680 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n"); 681 return ForwardIrpAndForget(DeviceObject, Irp); 682 } 683 default: 684 ERR_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 685 Stack->Parameters.QueryDeviceRelations.Type); 686 ASSERT(FALSE); 687 return ForwardIrpAndForget(DeviceObject, Irp); 688 } 689 break; 690 } 691 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0x0d */ 692 { 693 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); 694 /* Nothing to do */ 695 Status = Irp->IoStatus.Status; 696 break; 697 } 698 default: 699 { 700 ERR_(I8042PRT, "IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction); 701 ASSERT(FALSE); 702 return ForwardIrpAndForget(DeviceObject, Irp); 703 } 704 } 705 706 Irp->IoStatus.Information = Information; 707 Irp->IoStatus.Status = Status; 708 IoCompleteRequest(Irp, IO_NO_INCREMENT); 709 return Status; 710 } 711