Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpnp.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS i8042 (ps/2 keyboard-mouse controller) driver 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: drivers/input/i8042prt/pnp.c 00005 * PURPOSE: IRP_MJ_PNP operations 00006 * PROGRAMMERS: Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org) 00007 * Copyright 2008 Colin Finck (mail@colinfinck.de) 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include "i8042prt.h" 00013 00014 /* FUNCTIONS *****************************************************************/ 00015 00016 /* This is all pretty confusing. There's more than one way to 00017 * disable/enable the keyboard. You can send KBD_ENABLE to the 00018 * keyboard, and it will start scanning keys. Sending KBD_DISABLE 00019 * will disable the key scanning but also reset the parameters to 00020 * defaults. 00021 * 00022 * You can also send 0xAE to the controller for enabling the 00023 * keyboard clock line and 0xAD for disabling it. Then it'll 00024 * automatically get turned on at the next command. The last 00025 * way is by modifying the bit that drives the clock line in the 00026 * 'command byte' of the controller. This is almost, but not quite, 00027 * the same as the AE/AD thing. The difference can be used to detect 00028 * some really old broken keyboard controllers which I hope won't be 00029 * necessary. 00030 * 00031 * We change the command byte, sending KBD_ENABLE/DISABLE seems to confuse 00032 * some kvm switches. 00033 */ 00034 BOOLEAN 00035 i8042ChangeMode( 00036 IN PPORT_DEVICE_EXTENSION DeviceExtension, 00037 IN UCHAR FlagsToDisable, 00038 IN UCHAR FlagsToEnable) 00039 { 00040 UCHAR Value; 00041 NTSTATUS Status; 00042 00043 if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_READ_MODE)) 00044 { 00045 WARN_(I8042PRT, "Can't read i8042 mode\n"); 00046 return FALSE; 00047 } 00048 00049 Status = i8042ReadDataWait(DeviceExtension, &Value); 00050 if (!NT_SUCCESS(Status)) 00051 { 00052 WARN_(I8042PRT, "No response after read i8042 mode\n"); 00053 return FALSE; 00054 } 00055 00056 Value &= ~FlagsToDisable; 00057 Value |= FlagsToEnable; 00058 00059 if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, KBD_WRITE_MODE)) 00060 { 00061 WARN_(I8042PRT, "Can't set i8042 mode\n"); 00062 return FALSE; 00063 } 00064 00065 if (!i8042Write(DeviceExtension, DeviceExtension->DataPort, Value)) 00066 { 00067 WARN_(I8042PRT, "Can't send i8042 mode\n"); 00068 return FALSE; 00069 } 00070 00071 return TRUE; 00072 } 00073 00074 static NTSTATUS 00075 i8042BasicDetect( 00076 IN PPORT_DEVICE_EXTENSION DeviceExtension) 00077 { 00078 NTSTATUS Status; 00079 ULONG ResendIterations; 00080 UCHAR Value = 0; 00081 00082 /* Don't enable keyboard and mouse interrupts, disable keyboard/mouse */ 00083 i8042Flush(DeviceExtension); 00084 if (!i8042ChangeMode(DeviceExtension, CCB_KBD_INT_ENAB | CCB_MOUSE_INT_ENAB, CCB_KBD_DISAB | CCB_MOUSE_DISAB)) 00085 return STATUS_IO_DEVICE_ERROR; 00086 00087 i8042Flush(DeviceExtension); 00088 00089 /* Issue a CTRL_SELF_TEST command to check if this is really an i8042 controller */ 00090 ResendIterations = DeviceExtension->Settings.ResendIterations + 1; 00091 while (ResendIterations--) 00092 { 00093 if (!i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST)) 00094 { 00095 WARN_(I8042PRT, "Writing CTRL_SELF_TEST command failed\n"); 00096 return STATUS_IO_TIMEOUT; 00097 } 00098 00099 Status = i8042ReadDataWait(DeviceExtension, &Value); 00100 if (!NT_SUCCESS(Status)) 00101 { 00102 WARN_(I8042PRT, "Failed to read CTRL_SELF_TEST response, status 0x%08lx\n", Status); 00103 return Status; 00104 } 00105 00106 if (Value == KBD_SELF_TEST_OK) 00107 { 00108 INFO_(I8042PRT, "CTRL_SELF_TEST completed successfully!\n"); 00109 break; 00110 } 00111 else if (Value == KBD_RESEND) 00112 { 00113 TRACE_(I8042PRT, "Resending...\n", Value); 00114 KeStallExecutionProcessor(50); 00115 } 00116 else 00117 { 00118 WARN_(I8042PRT, "Got 0x%02x instead of 0x55\n", Value); 00119 return STATUS_IO_DEVICE_ERROR; 00120 } 00121 } 00122 00123 return STATUS_SUCCESS; 00124 } 00125 00126 static VOID 00127 i8042DetectKeyboard( 00128 IN PPORT_DEVICE_EXTENSION DeviceExtension) 00129 { 00130 NTSTATUS Status; 00131 00132 /* Set LEDs (that is not fatal if some error occurs) */ 00133 Status = i8042SynchWritePort(DeviceExtension, 0, KBD_CMD_SET_LEDS, TRUE); 00134 if (NT_SUCCESS(Status)) 00135 { 00136 Status = i8042SynchWritePort(DeviceExtension, 0, 0, TRUE); 00137 if (!NT_SUCCESS(Status)) 00138 { 00139 WARN_(I8042PRT, "Can't finish SET_LEDS (0x%08lx)\n", Status); 00140 return; 00141 } 00142 } 00143 else 00144 { 00145 WARN_(I8042PRT, "Warning: can't write SET_LEDS (0x%08lx)\n", Status); 00146 } 00147 00148 /* Turn on translation and SF (Some machines don't reboot if SF is not set, see ReactOS bug #1842) */ 00149 if (!i8042ChangeMode(DeviceExtension, 0, CCB_TRANSLATE | CCB_SYSTEM_FLAG)) 00150 return; 00151 00152 /* 00153 * We used to send a KBD_LINE_TEST (0xAB) command, but on at least HP 00154 * Pavilion notebooks the response to that command was incorrect. 00155 * So now we just assume that a keyboard is attached. 00156 */ 00157 DeviceExtension->Flags |= KEYBOARD_PRESENT; 00158 00159 INFO_(I8042PRT, "Keyboard detected\n"); 00160 } 00161 00162 static VOID 00163 i8042DetectMouse( 00164 IN PPORT_DEVICE_EXTENSION DeviceExtension) 00165 { 00166 NTSTATUS Status; 00167 UCHAR Value; 00168 UCHAR ExpectedReply[] = { MOUSE_ACK, 0xAA }; 00169 UCHAR ReplyByte; 00170 00171 /* First do a mouse line test */ 00172 if (i8042Write(DeviceExtension, DeviceExtension->ControlPort, MOUSE_LINE_TEST)) 00173 { 00174 Status = i8042ReadDataWait(DeviceExtension, &Value); 00175 00176 if (!NT_SUCCESS(Status) || Value != 0) 00177 { 00178 WARN_(I8042PRT, "Mouse line test failed\n"); 00179 goto failure; 00180 } 00181 } 00182 00183 /* Now reset the mouse */ 00184 i8042Flush(DeviceExtension); 00185 00186 if(!i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE)) 00187 { 00188 WARN_(I8042PRT, "Failed to write reset command to mouse\n"); 00189 goto failure; 00190 } 00191 00192 /* The implementation of the "Mouse Reset" command differs much from chip to chip. 00193 00194 By default, the first byte is an ACK, when the mouse is plugged in and working and NACK when it's not. 00195 On success, the next bytes are 0xAA and 0x00. 00196 00197 But on some systems (like ECS K7S5A Pro, SiS 735 chipset), we always get an ACK and 0xAA. 00198 Only the last byte indicates, whether a mouse is plugged in. 00199 It is either sent or not, so there is no byte, which indicates a failure here. 00200 00201 After the Mouse Reset command was issued, it usually takes some time until we get a response. 00202 So get the first two bytes in a loop. */ 00203 for (ReplyByte = 0; 00204 ReplyByte < sizeof(ExpectedReply) / sizeof(ExpectedReply[0]); 00205 ReplyByte++) 00206 { 00207 ULONG Counter = 500; 00208 00209 do 00210 { 00211 Status = i8042ReadDataWait(DeviceExtension, &Value); 00212 00213 if(!NT_SUCCESS(Status)) 00214 { 00215 /* Wait some time before trying again */ 00216 KeStallExecutionProcessor(50); 00217 } 00218 } while (Status == STATUS_IO_TIMEOUT && Counter--); 00219 00220 if (!NT_SUCCESS(Status)) 00221 { 00222 WARN_(I8042PRT, "No ACK after mouse reset, status 0x%08lx\n", Status); 00223 goto failure; 00224 } 00225 else if (Value != ExpectedReply[ReplyByte]) 00226 { 00227 WARN_(I8042PRT, "Unexpected reply: 0x%02x (expected 0x%02x)\n", Value, ExpectedReply[ReplyByte]); 00228 goto failure; 00229 } 00230 } 00231 00232 /* Finally get the third byte, but only try it one time (see above). 00233 Otherwise this takes around 45 seconds on a K7S5A Pro, when no mouse is plugged in. */ 00234 Status = i8042ReadDataWait(DeviceExtension, &Value); 00235 00236 if(!NT_SUCCESS(Status)) 00237 { 00238 WARN_(I8042PRT, "Last byte was not transmitted after mouse reset, status 0x%08lx\n", Status); 00239 goto failure; 00240 } 00241 else if(Value != 0x00) 00242 { 00243 WARN_(I8042PRT, "Last byte after mouse reset was not 0x00, but 0x%02x\n", Value); 00244 goto failure; 00245 } 00246 00247 DeviceExtension->Flags |= MOUSE_PRESENT; 00248 INFO_(I8042PRT, "Mouse detected\n"); 00249 return; 00250 00251 failure: 00252 /* There is probably no mouse present. On some systems, 00253 the probe locks the entire keyboard controller. Let's 00254 try to get access to the keyboard again by sending a 00255 reset */ 00256 i8042Flush(DeviceExtension); 00257 i8042Write(DeviceExtension, DeviceExtension->ControlPort, CTRL_SELF_TEST); 00258 i8042ReadDataWait(DeviceExtension, &Value); 00259 i8042Flush(DeviceExtension); 00260 00261 INFO_(I8042PRT, "Mouse not detected\n"); 00262 } 00263 00264 static NTSTATUS 00265 i8042ConnectKeyboardInterrupt( 00266 IN PI8042_KEYBOARD_EXTENSION DeviceExtension) 00267 { 00268 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00269 KIRQL DirqlMax; 00270 NTSTATUS Status; 00271 00272 TRACE_(I8042PRT, "i8042ConnectKeyboardInterrupt()\n"); 00273 00274 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00275 DirqlMax = MAX( 00276 PortDeviceExtension->KeyboardInterrupt.Dirql, 00277 PortDeviceExtension->MouseInterrupt.Dirql); 00278 00279 INFO_(I8042PRT, "KeyboardInterrupt.Vector %lu\n", 00280 PortDeviceExtension->KeyboardInterrupt.Vector); 00281 INFO_(I8042PRT, "KeyboardInterrupt.Dirql %lu\n", 00282 PortDeviceExtension->KeyboardInterrupt.Dirql); 00283 INFO_(I8042PRT, "KeyboardInterrupt.DirqlMax %lu\n", 00284 DirqlMax); 00285 INFO_(I8042PRT, "KeyboardInterrupt.InterruptMode %s\n", 00286 PortDeviceExtension->KeyboardInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched"); 00287 INFO_(I8042PRT, "KeyboardInterrupt.ShareInterrupt %s\n", 00288 PortDeviceExtension->KeyboardInterrupt.ShareInterrupt ? "yes" : "no"); 00289 INFO_(I8042PRT, "KeyboardInterrupt.Affinity 0x%lx\n", 00290 PortDeviceExtension->KeyboardInterrupt.Affinity); 00291 Status = IoConnectInterrupt( 00292 &PortDeviceExtension->KeyboardInterrupt.Object, 00293 i8042KbdInterruptService, 00294 DeviceExtension, &PortDeviceExtension->SpinLock, 00295 PortDeviceExtension->KeyboardInterrupt.Vector, PortDeviceExtension->KeyboardInterrupt.Dirql, DirqlMax, 00296 PortDeviceExtension->KeyboardInterrupt.InterruptMode, PortDeviceExtension->KeyboardInterrupt.ShareInterrupt, 00297 PortDeviceExtension->KeyboardInterrupt.Affinity, FALSE); 00298 if (!NT_SUCCESS(Status)) 00299 { 00300 WARN_(I8042PRT, "IoConnectInterrupt() failed with status 0x%08x\n", Status); 00301 return Status; 00302 } 00303 00304 if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql) 00305 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object; 00306 PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED; 00307 return STATUS_SUCCESS; 00308 } 00309 00310 static NTSTATUS 00311 i8042ConnectMouseInterrupt( 00312 IN PI8042_MOUSE_EXTENSION DeviceExtension) 00313 { 00314 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00315 KIRQL DirqlMax; 00316 NTSTATUS Status; 00317 00318 TRACE_(I8042PRT, "i8042ConnectMouseInterrupt()\n"); 00319 00320 Status = i8042MouInitialize(DeviceExtension); 00321 if (!NT_SUCCESS(Status)) 00322 return Status; 00323 00324 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00325 DirqlMax = MAX( 00326 PortDeviceExtension->KeyboardInterrupt.Dirql, 00327 PortDeviceExtension->MouseInterrupt.Dirql); 00328 00329 INFO_(I8042PRT, "MouseInterrupt.Vector %lu\n", 00330 PortDeviceExtension->MouseInterrupt.Vector); 00331 INFO_(I8042PRT, "MouseInterrupt.Dirql %lu\n", 00332 PortDeviceExtension->MouseInterrupt.Dirql); 00333 INFO_(I8042PRT, "MouseInterrupt.DirqlMax %lu\n", 00334 DirqlMax); 00335 INFO_(I8042PRT, "MouseInterrupt.InterruptMode %s\n", 00336 PortDeviceExtension->MouseInterrupt.InterruptMode == LevelSensitive ? "LevelSensitive" : "Latched"); 00337 INFO_(I8042PRT, "MouseInterrupt.ShareInterrupt %s\n", 00338 PortDeviceExtension->MouseInterrupt.ShareInterrupt ? "yes" : "no"); 00339 INFO_(I8042PRT, "MouseInterrupt.Affinity 0x%lx\n", 00340 PortDeviceExtension->MouseInterrupt.Affinity); 00341 Status = IoConnectInterrupt( 00342 &PortDeviceExtension->MouseInterrupt.Object, 00343 i8042MouInterruptService, 00344 DeviceExtension, &PortDeviceExtension->SpinLock, 00345 PortDeviceExtension->MouseInterrupt.Vector, PortDeviceExtension->MouseInterrupt.Dirql, DirqlMax, 00346 PortDeviceExtension->MouseInterrupt.InterruptMode, PortDeviceExtension->MouseInterrupt.ShareInterrupt, 00347 PortDeviceExtension->MouseInterrupt.Affinity, FALSE); 00348 if (!NT_SUCCESS(Status)) 00349 { 00350 WARN_(I8042PRT, "IoConnectInterrupt() failed with status 0x%08x\n", Status); 00351 goto cleanup; 00352 } 00353 00354 if (DirqlMax == PortDeviceExtension->MouseInterrupt.Dirql) 00355 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->MouseInterrupt.Object; 00356 00357 PortDeviceExtension->Flags |= MOUSE_INITIALIZED; 00358 Status = STATUS_SUCCESS; 00359 00360 cleanup: 00361 if (!NT_SUCCESS(Status)) 00362 { 00363 PortDeviceExtension->Flags &= ~MOUSE_INITIALIZED; 00364 if (PortDeviceExtension->MouseInterrupt.Object) 00365 { 00366 IoDisconnectInterrupt(PortDeviceExtension->MouseInterrupt.Object); 00367 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object; 00368 } 00369 } 00370 return Status; 00371 } 00372 00373 static NTSTATUS 00374 EnableInterrupts( 00375 IN PPORT_DEVICE_EXTENSION DeviceExtension, 00376 IN UCHAR FlagsToDisable, 00377 IN UCHAR FlagsToEnable) 00378 { 00379 i8042Flush(DeviceExtension); 00380 00381 if (!i8042ChangeMode(DeviceExtension, FlagsToDisable, FlagsToEnable)) 00382 return STATUS_UNSUCCESSFUL; 00383 00384 return STATUS_SUCCESS; 00385 } 00386 00387 static NTSTATUS 00388 StartProcedure( 00389 IN PPORT_DEVICE_EXTENSION DeviceExtension) 00390 { 00391 NTSTATUS Status; 00392 UCHAR FlagsToDisable = 0; 00393 UCHAR FlagsToEnable = 0; 00394 KIRQL Irql; 00395 00396 if (DeviceExtension->DataPort == 0) 00397 { 00398 /* Unable to do something at the moment */ 00399 return STATUS_SUCCESS; 00400 } 00401 00402 if (!(DeviceExtension->Flags & (KEYBOARD_PRESENT | MOUSE_PRESENT))) 00403 { 00404 /* Try to detect them */ 00405 TRACE_(I8042PRT, "Check if the controller is really a i8042\n"); 00406 Status = i8042BasicDetect(DeviceExtension); 00407 if (!NT_SUCCESS(Status)) 00408 { 00409 WARN_(I8042PRT, "i8042BasicDetect() failed with status 0x%08lx\n", Status); 00410 return STATUS_UNSUCCESSFUL; 00411 } 00412 00413 /* First detect the mouse and then the keyboard! 00414 If we do it the other way round, some systems throw away settings like the keyboard translation, when detecting the mouse. */ 00415 TRACE_(I8042PRT, "Detecting mouse\n"); 00416 i8042DetectMouse(DeviceExtension); 00417 TRACE_(I8042PRT, "Detecting keyboard\n"); 00418 i8042DetectKeyboard(DeviceExtension); 00419 00420 INFO_(I8042PRT, "Keyboard present: %s\n", DeviceExtension->Flags & KEYBOARD_PRESENT ? "YES" : "NO"); 00421 INFO_(I8042PRT, "Mouse present : %s\n", DeviceExtension->Flags & MOUSE_PRESENT ? "YES" : "NO"); 00422 00423 TRACE_(I8042PRT, "Enabling i8042 interrupts\n"); 00424 if (DeviceExtension->Flags & KEYBOARD_PRESENT) 00425 { 00426 FlagsToDisable |= CCB_KBD_DISAB; 00427 FlagsToEnable |= CCB_KBD_INT_ENAB; 00428 } 00429 if (DeviceExtension->Flags & MOUSE_PRESENT) 00430 { 00431 FlagsToDisable |= CCB_MOUSE_DISAB; 00432 FlagsToEnable |= CCB_MOUSE_INT_ENAB; 00433 } 00434 00435 Status = EnableInterrupts(DeviceExtension, FlagsToDisable, FlagsToEnable); 00436 if (!NT_SUCCESS(Status)) 00437 { 00438 DeviceExtension->Flags &= ~(KEYBOARD_PRESENT | MOUSE_PRESENT); 00439 return Status; 00440 } 00441 } 00442 00443 /* Connect interrupts */ 00444 if (DeviceExtension->Flags & KEYBOARD_PRESENT && 00445 DeviceExtension->Flags & KEYBOARD_CONNECTED && 00446 DeviceExtension->Flags & KEYBOARD_STARTED && 00447 !(DeviceExtension->Flags & KEYBOARD_INITIALIZED)) 00448 { 00449 /* Keyboard is ready to be initialized */ 00450 Status = i8042ConnectKeyboardInterrupt(DeviceExtension->KeyboardExtension); 00451 if (NT_SUCCESS(Status)) 00452 { 00453 DeviceExtension->Flags |= KEYBOARD_INITIALIZED; 00454 } 00455 } 00456 00457 if (DeviceExtension->Flags & MOUSE_PRESENT && 00458 DeviceExtension->Flags & MOUSE_CONNECTED && 00459 DeviceExtension->Flags & MOUSE_STARTED && 00460 !(DeviceExtension->Flags & MOUSE_INITIALIZED)) 00461 { 00462 /* Mouse is ready to be initialized */ 00463 Status = i8042ConnectMouseInterrupt(DeviceExtension->MouseExtension); 00464 if (NT_SUCCESS(Status)) 00465 { 00466 DeviceExtension->Flags |= MOUSE_INITIALIZED; 00467 } 00468 00469 /* Start the mouse */ 00470 Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt); 00471 i8042IsrWritePort(DeviceExtension, MOU_CMD_RESET, CTRL_WRITE_MOUSE); 00472 KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql); 00473 } 00474 00475 return Status; 00476 } 00477 00478 static NTSTATUS 00479 i8042PnpStartDevice( 00480 IN PDEVICE_OBJECT DeviceObject, 00481 IN PCM_RESOURCE_LIST AllocatedResources, 00482 IN PCM_RESOURCE_LIST AllocatedResourcesTranslated) 00483 { 00484 PFDO_DEVICE_EXTENSION DeviceExtension; 00485 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00486 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor, ResourceDescriptorTranslated; 00487 INTERRUPT_DATA InterruptData; 00488 BOOLEAN FoundDataPort = FALSE; 00489 BOOLEAN FoundControlPort = FALSE; 00490 BOOLEAN FoundIrq = FALSE; 00491 ULONG i; 00492 NTSTATUS Status; 00493 00494 TRACE_(I8042PRT, "i8042PnpStartDevice(%p)\n", DeviceObject); 00495 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 00496 PortDeviceExtension = DeviceExtension->PortDeviceExtension; 00497 00498 ASSERT(DeviceExtension->PnpState == dsStopped); 00499 00500 if (!AllocatedResources) 00501 { 00502 WARN_(I8042PRT, "No allocated resources sent to driver\n"); 00503 return STATUS_INSUFFICIENT_RESOURCES; 00504 } 00505 if (AllocatedResources->Count != 1) 00506 { 00507 WARN_(I8042PRT, "Wrong number of allocated resources sent to driver\n"); 00508 return STATUS_INSUFFICIENT_RESOURCES; 00509 } 00510 if (AllocatedResources->List[0].PartialResourceList.Version != 1 00511 || AllocatedResources->List[0].PartialResourceList.Revision != 1 00512 || AllocatedResourcesTranslated->List[0].PartialResourceList.Version != 1 00513 || AllocatedResourcesTranslated->List[0].PartialResourceList.Revision != 1) 00514 { 00515 WARN_(I8042PRT, "Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n", 00516 AllocatedResources->List[0].PartialResourceList.Version, 00517 AllocatedResources->List[0].PartialResourceList.Revision, 00518 AllocatedResourcesTranslated->List[0].PartialResourceList.Version, 00519 AllocatedResourcesTranslated->List[0].PartialResourceList.Revision); 00520 return STATUS_REVISION_MISMATCH; 00521 } 00522 00523 /* Get Irq and optionally control port and data port */ 00524 for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++) 00525 { 00526 ResourceDescriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i]; 00527 ResourceDescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i]; 00528 switch (ResourceDescriptor->Type) 00529 { 00530 case CmResourceTypePort: 00531 { 00532 if (ResourceDescriptor->u.Port.Length == 1) 00533 { 00534 /* We assume that the first ressource will 00535 * be the control port and the second one 00536 * will be the data port... 00537 */ 00538 if (!FoundDataPort) 00539 { 00540 PortDeviceExtension->DataPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart); 00541 INFO_(I8042PRT, "Found data port: %p\n", PortDeviceExtension->DataPort); 00542 FoundDataPort = TRUE; 00543 } 00544 else if (!FoundControlPort) 00545 { 00546 PortDeviceExtension->ControlPort = ULongToPtr(ResourceDescriptor->u.Port.Start.u.LowPart); 00547 INFO_(I8042PRT, "Found control port: %p\n", PortDeviceExtension->ControlPort); 00548 FoundControlPort = TRUE; 00549 } 00550 else 00551 { 00552 WARN_(I8042PRT, "Too much I/O ranges provided: 0x%lx\n", ResourceDescriptor->u.Port.Length); 00553 return STATUS_INVALID_PARAMETER; 00554 } 00555 } 00556 else 00557 WARN_(I8042PRT, "Invalid I/O range length: 0x%lx\n", ResourceDescriptor->u.Port.Length); 00558 break; 00559 } 00560 case CmResourceTypeInterrupt: 00561 { 00562 if (FoundIrq) 00563 return STATUS_INVALID_PARAMETER; 00564 InterruptData.Dirql = (KIRQL)ResourceDescriptorTranslated->u.Interrupt.Level; 00565 InterruptData.Vector = ResourceDescriptorTranslated->u.Interrupt.Vector; 00566 InterruptData.Affinity = ResourceDescriptorTranslated->u.Interrupt.Affinity; 00567 if (ResourceDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED) 00568 InterruptData.InterruptMode = Latched; 00569 else 00570 InterruptData.InterruptMode = LevelSensitive; 00571 InterruptData.ShareInterrupt = (ResourceDescriptorTranslated->ShareDisposition == CmResourceShareShared); 00572 INFO_(I8042PRT, "Found irq resource: %lu\n", ResourceDescriptor->u.Interrupt.Level); 00573 FoundIrq = TRUE; 00574 break; 00575 } 00576 default: 00577 WARN_(I8042PRT, "Unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type); 00578 } 00579 } 00580 00581 if (!FoundIrq) 00582 { 00583 WARN_(I8042PRT, "Interrupt resource was not found in allocated resources list\n"); 00584 return STATUS_INSUFFICIENT_RESOURCES; 00585 } 00586 else if (DeviceExtension->Type == Keyboard && (!FoundDataPort || !FoundControlPort)) 00587 { 00588 WARN_(I8042PRT, "Some required resources were not found in allocated resources list\n"); 00589 return STATUS_INSUFFICIENT_RESOURCES; 00590 } 00591 else if (DeviceExtension->Type == Mouse && (FoundDataPort || FoundControlPort)) 00592 { 00593 WARN_(I8042PRT, "Too much resources were provided in allocated resources list\n"); 00594 return STATUS_INVALID_PARAMETER; 00595 } 00596 00597 switch (DeviceExtension->Type) 00598 { 00599 case Keyboard: 00600 { 00601 RtlCopyMemory( 00602 &PortDeviceExtension->KeyboardInterrupt, 00603 &InterruptData, 00604 sizeof(INTERRUPT_DATA)); 00605 PortDeviceExtension->Flags |= KEYBOARD_STARTED; 00606 Status = StartProcedure(PortDeviceExtension); 00607 break; 00608 } 00609 case Mouse: 00610 { 00611 RtlCopyMemory( 00612 &PortDeviceExtension->MouseInterrupt, 00613 &InterruptData, 00614 sizeof(INTERRUPT_DATA)); 00615 PortDeviceExtension->Flags |= MOUSE_STARTED; 00616 Status = StartProcedure(PortDeviceExtension); 00617 break; 00618 } 00619 default: 00620 { 00621 WARN_(I8042PRT, "Unknown FDO type %u\n", DeviceExtension->Type); 00622 ASSERT(!(PortDeviceExtension->Flags & KEYBOARD_CONNECTED) || !(PortDeviceExtension->Flags & MOUSE_CONNECTED)); 00623 Status = STATUS_INVALID_DEVICE_REQUEST; 00624 } 00625 } 00626 00627 if (NT_SUCCESS(Status)) 00628 DeviceExtension->PnpState = dsStarted; 00629 00630 return Status; 00631 } 00632 00633 NTSTATUS NTAPI 00634 i8042Pnp( 00635 IN PDEVICE_OBJECT DeviceObject, 00636 IN PIRP Irp) 00637 { 00638 PIO_STACK_LOCATION Stack; 00639 ULONG MinorFunction; 00640 I8042_DEVICE_TYPE DeviceType; 00641 ULONG_PTR Information = 0; 00642 NTSTATUS Status; 00643 00644 Stack = IoGetCurrentIrpStackLocation(Irp); 00645 MinorFunction = Stack->MinorFunction; 00646 DeviceType = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->Type; 00647 00648 switch (MinorFunction) 00649 { 00650 case IRP_MN_START_DEVICE: /* 0x00 */ 00651 { 00652 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 00653 00654 /* Call lower driver (if any) */ 00655 if (DeviceType != PhysicalDeviceObject) 00656 { 00657 Status = ForwardIrpAndWait(DeviceObject, Irp); 00658 if (NT_SUCCESS(Status)) 00659 Status = i8042PnpStartDevice( 00660 DeviceObject, 00661 Stack->Parameters.StartDevice.AllocatedResources, 00662 Stack->Parameters.StartDevice.AllocatedResourcesTranslated); 00663 } 00664 else 00665 Status = STATUS_SUCCESS; 00666 break; 00667 } 00668 case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x07 */ 00669 { 00670 switch (Stack->Parameters.QueryDeviceRelations.Type) 00671 { 00672 case BusRelations: 00673 { 00674 PDEVICE_RELATIONS DeviceRelations; 00675 00676 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); 00677 DeviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS)); 00678 if (DeviceRelations) 00679 { 00680 DeviceRelations->Count = 0; 00681 Information = (ULONG_PTR)DeviceRelations; 00682 Status = STATUS_SUCCESS; 00683 } 00684 else 00685 Status = STATUS_INSUFFICIENT_RESOURCES; 00686 break; 00687 } 00688 case RemovalRelations: 00689 { 00690 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n"); 00691 return ForwardIrpAndForget(DeviceObject, Irp); 00692 } 00693 default: 00694 ERR_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 00695 Stack->Parameters.QueryDeviceRelations.Type); 00696 ASSERT(FALSE); 00697 return ForwardIrpAndForget(DeviceObject, Irp); 00698 } 00699 break; 00700 } 00701 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* (optional) 0x0d */ 00702 { 00703 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); 00704 /* Nothing to do */ 00705 Status = Irp->IoStatus.Status; 00706 break; 00707 } 00708 case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */ 00709 { 00710 TRACE_(I8042PRT, "IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n"); 00711 /* Nothing much to tell */ 00712 Information = 0; 00713 Status = STATUS_SUCCESS; 00714 break; 00715 } 00716 default: 00717 { 00718 ERR_(I8042PRT, "IRP_MJ_PNP / unknown minor function 0x%x\n", MinorFunction); 00719 return ForwardIrpAndForget(DeviceObject, Irp); 00720 } 00721 } 00722 00723 Irp->IoStatus.Information = Information; 00724 Irp->IoStatus.Status = Status; 00725 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00726 return Status; 00727 } Generated on Sun May 27 2012 04:17:51 for ReactOS by
1.7.6.1
|