Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenkeyboard.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/keyboard.c 00005 * PURPOSE: Keyboard specific functions 00006 * PROGRAMMERS: Copyright Victor Kirhenshtein (sauros@iname.com) 00007 Copyright Jason Filby (jasonfilby@yahoo.com) 00008 Copyright Martijn Vernooij (o112w8r02@sneakemail.com) 00009 Copyright 2006-2007 Hervé Poussineau (hpoussin@reactos.org) 00010 */ 00011 00012 /* INCLUDES ****************************************************************/ 00013 00014 #include "i8042prt.h" 00015 00016 /* GLOBALS *******************************************************************/ 00017 00018 static IO_WORKITEM_ROUTINE i8042PowerWorkItem; 00019 00020 /* This structure starts with the same layout as KEYBOARD_INDICATOR_TRANSLATION */ 00021 typedef struct _LOCAL_KEYBOARD_INDICATOR_TRANSLATION { 00022 USHORT NumberOfIndicatorKeys; 00023 INDICATOR_LIST IndicatorList[3]; 00024 } LOCAL_KEYBOARD_INDICATOR_TRANSLATION, *PLOCAL_KEYBOARD_INDICATOR_TRANSLATION; 00025 00026 static LOCAL_KEYBOARD_INDICATOR_TRANSLATION IndicatorTranslation = { 3, { 00027 {0x3A, KEYBOARD_CAPS_LOCK_ON}, 00028 {0x45, KEYBOARD_NUM_LOCK_ON}, 00029 {0x46, KEYBOARD_SCROLL_LOCK_ON}}}; 00030 00031 /* FUNCTIONS *****************************************************************/ 00032 00033 /* 00034 * These functions are callbacks for filter driver custom interrupt 00035 * service routines. 00036 */ 00037 /*static VOID NTAPI 00038 i8042KbdIsrWritePort( 00039 IN PVOID Context, 00040 IN UCHAR Value) 00041 { 00042 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00043 00044 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context; 00045 00046 if (DeviceExtension->KeyboardHook.IsrWritePort) 00047 { 00048 DeviceExtension->KeyboardHook.IsrWritePort( 00049 DeviceExtension->KeyboardHook.CallContext, 00050 Value); 00051 } 00052 else 00053 i8042IsrWritePort(Context, Value, 0); 00054 }*/ 00055 00056 static VOID NTAPI 00057 i8042KbdQueuePacket( 00058 IN PVOID Context) 00059 { 00060 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00061 00062 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context; 00063 00064 DeviceExtension->KeyComplete = TRUE; 00065 DeviceExtension->KeysInBuffer++; 00066 if (DeviceExtension->KeysInBuffer > DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize) 00067 { 00068 WARN_(I8042PRT, "Keyboard buffer overflow\n"); 00069 DeviceExtension->KeysInBuffer--; 00070 } 00071 00072 TRACE_(I8042PRT, "Irq completes key\n"); 00073 KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL); 00074 } 00075 00076 /* 00077 * These functions are callbacks for filter driver custom 00078 * initialization routines. 00079 */ 00080 NTSTATUS NTAPI 00081 i8042SynchWritePortKbd( 00082 IN PVOID Context, 00083 IN UCHAR Value, 00084 IN BOOLEAN WaitForAck) 00085 { 00086 return i8042SynchWritePort( 00087 (PPORT_DEVICE_EXTENSION)Context, 00088 0, 00089 Value, 00090 WaitForAck); 00091 } 00092 00093 /* 00094 * Process the keyboard internal device requests 00095 */ 00096 VOID NTAPI 00097 i8042KbdStartIo( 00098 IN PDEVICE_OBJECT DeviceObject, 00099 IN PIRP Irp) 00100 { 00101 PIO_STACK_LOCATION Stack; 00102 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00103 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00104 00105 Stack = IoGetCurrentIrpStackLocation(Irp); 00106 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension; 00107 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00108 00109 switch (Stack->Parameters.DeviceIoControl.IoControlCode) 00110 { 00111 case IOCTL_KEYBOARD_SET_INDICATORS: 00112 { 00113 TRACE_(I8042PRT, "IOCTL_KEYBOARD_SET_INDICATORS\n"); 00114 INFO_(I8042PRT, "Leds: {%s%s%s }\n", 00115 DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON ? " CAPSLOCK" : "", 00116 DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON ? " NUMLOCK" : "", 00117 DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON ? " SCROLLLOCK" : ""); 00118 00119 PortDeviceExtension->PacketBuffer[0] = KBD_CMD_SET_LEDS; 00120 PortDeviceExtension->PacketBuffer[1] = 0; 00121 if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON) 00122 PortDeviceExtension->PacketBuffer[1] |= KBD_LED_CAPS; 00123 00124 if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON) 00125 PortDeviceExtension->PacketBuffer[1] |= KBD_LED_NUM; 00126 00127 if (DeviceExtension->KeyboardIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON) 00128 PortDeviceExtension->PacketBuffer[1] |= KBD_LED_SCROLL; 00129 00130 i8042StartPacket( 00131 PortDeviceExtension, 00132 &DeviceExtension->Common, 00133 PortDeviceExtension->PacketBuffer, 00134 2, 00135 Irp); 00136 break; 00137 } 00138 default: 00139 { 00140 ERR_(I8042PRT, "Unknown ioctl code 0x%lx\n", 00141 Stack->Parameters.DeviceIoControl.IoControlCode); 00142 ASSERT(FALSE); 00143 } 00144 } 00145 } 00146 00147 static VOID 00148 i8042PacketDpc( 00149 IN PPORT_DEVICE_EXTENSION DeviceExtension) 00150 { 00151 BOOLEAN FinishIrp = FALSE; 00152 KIRQL Irql; 00153 NTSTATUS Result = STATUS_INTERNAL_ERROR; /* Shouldn't happen */ 00154 00155 /* If the interrupt happens before this is setup, the key 00156 * was already in the buffer. Too bad! */ 00157 if (!DeviceExtension->HighestDIRQLInterrupt) 00158 return; 00159 00160 Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt); 00161 00162 if (DeviceExtension->Packet.State == Idle 00163 && DeviceExtension->PacketComplete) 00164 { 00165 FinishIrp = TRUE; 00166 Result = DeviceExtension->PacketResult; 00167 DeviceExtension->PacketComplete = FALSE; 00168 } 00169 00170 KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql); 00171 00172 if (!FinishIrp) 00173 return; 00174 00175 if (DeviceExtension->CurrentIrp) 00176 { 00177 DeviceExtension->CurrentIrp->IoStatus.Status = Result; 00178 IoCompleteRequest(DeviceExtension->CurrentIrp, IO_NO_INCREMENT); 00179 IoStartNextPacket(DeviceExtension->CurrentIrpDevice, FALSE); 00180 DeviceExtension->CurrentIrp = NULL; 00181 DeviceExtension->CurrentIrpDevice = NULL; 00182 } 00183 } 00184 00185 static VOID NTAPI 00186 i8042PowerWorkItem( 00187 IN PDEVICE_OBJECT DeviceObject, 00188 IN PVOID Context) 00189 { 00190 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00191 PIRP WaitingIrp; 00192 NTSTATUS Status; 00193 00194 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context; 00195 00196 UNREFERENCED_PARAMETER(DeviceObject); 00197 00198 /* See http://blogs.msdn.com/doronh/archive/2006/09/08/746961.aspx */ 00199 00200 /* Register GUID_DEVICE_SYS_BUTTON interface and report capability */ 00201 if (DeviceExtension->NewCaps != DeviceExtension->ReportedCaps) 00202 { 00203 WaitingIrp = InterlockedExchangePointer((PVOID)&DeviceExtension->PowerIrp, NULL); 00204 if (WaitingIrp) 00205 { 00206 /* Cancel the current power irp, as capability changed */ 00207 WaitingIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; 00208 WaitingIrp->IoStatus.Information = sizeof(ULONG); 00209 IoCompleteRequest(WaitingIrp, IO_NO_INCREMENT); 00210 } 00211 00212 if (DeviceExtension->PowerInterfaceName.MaximumLength == 0) 00213 { 00214 /* We have never registred this interface ; do it */ 00215 Status = IoRegisterDeviceInterface( 00216 DeviceExtension->Common.Pdo, 00217 &GUID_DEVICE_SYS_BUTTON, 00218 NULL, 00219 &DeviceExtension->PowerInterfaceName); 00220 if (!NT_SUCCESS(Status)) 00221 { 00222 /* We can't do more yet, ignore the keypress... */ 00223 WARN_(I8042PRT, "IoRegisterDeviceInterface(GUID_DEVICE_SYS_BUTTON) failed with status 0x%08lx\n", 00224 Status); 00225 DeviceExtension->PowerInterfaceName.MaximumLength = 0; 00226 return; 00227 } 00228 } 00229 else 00230 { 00231 /* Disable the interface. Once activated again, capabilities would be asked again */ 00232 Status = IoSetDeviceInterfaceState( 00233 &DeviceExtension->PowerInterfaceName, 00234 FALSE); 00235 if (!NT_SUCCESS(Status)) 00236 { 00237 /* Ignore the key press... */ 00238 WARN_(I8042PRT, "Disabling interface %wZ failed with status 0x%08lx\n", 00239 &DeviceExtension->PowerInterfaceName, Status); 00240 return; 00241 } 00242 } 00243 /* Enable the interface. This leads to receving a IOCTL_GET_SYS_BUTTON_CAPS, 00244 * so we can report new capability */ 00245 Status = IoSetDeviceInterfaceState( 00246 &DeviceExtension->PowerInterfaceName, 00247 TRUE); 00248 if (!NT_SUCCESS(Status)) 00249 { 00250 /* Ignore the key press... */ 00251 WARN_(I8042PRT, "Enabling interface %wZ failed with status 0x%08lx\n", 00252 &DeviceExtension->PowerInterfaceName, Status); 00253 return; 00254 } 00255 } 00256 00257 /* Directly complete the IOCTL_GET_SYS_BUTTON_EVENT Irp (if any) */ 00258 WaitingIrp = InterlockedExchangePointer((PVOID)&DeviceExtension->PowerIrp, NULL); 00259 if (WaitingIrp) 00260 { 00261 PULONG pEvent = (PULONG)WaitingIrp->AssociatedIrp.SystemBuffer; 00262 00263 WaitingIrp->IoStatus.Status = STATUS_SUCCESS; 00264 WaitingIrp->IoStatus.Information = sizeof(ULONG); 00265 *pEvent = InterlockedExchange((PLONG)&DeviceExtension->LastPowerKey, 0); 00266 IoCompleteRequest(WaitingIrp, IO_NO_INCREMENT); 00267 } 00268 } 00269 00270 /* Return TRUE if it was a power key */ 00271 static BOOLEAN 00272 HandlePowerKeys( 00273 IN PI8042_KEYBOARD_EXTENSION DeviceExtension) 00274 { 00275 PKEYBOARD_INPUT_DATA InputData; 00276 ULONG KeyPress; 00277 00278 InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer - 1; 00279 if (!(InputData->Flags & KEY_E0)) 00280 return FALSE; 00281 00282 switch (InputData->MakeCode) 00283 { 00284 case KEYBOARD_POWER_CODE: 00285 KeyPress = SYS_BUTTON_POWER; 00286 break; 00287 case KEYBOARD_SLEEP_CODE: 00288 KeyPress = SYS_BUTTON_SLEEP; 00289 break; 00290 case KEYBOARD_WAKE_CODE: 00291 KeyPress = SYS_BUTTON_WAKE; 00292 break; 00293 default: 00294 return FALSE; 00295 } 00296 00297 if (InputData->Flags & KEY_BREAK) 00298 /* We already took care of the key press */ 00299 return TRUE; 00300 00301 /* Our work can only be done at passive level, so use a workitem */ 00302 DeviceExtension->NewCaps |= KeyPress; 00303 InterlockedExchange((PLONG)&DeviceExtension->LastPowerKey, KeyPress); 00304 IoQueueWorkItem( 00305 DeviceExtension->PowerWorkItem, 00306 &i8042PowerWorkItem, 00307 DelayedWorkQueue, 00308 DeviceExtension); 00309 return TRUE; 00310 } 00311 00312 static VOID NTAPI 00313 i8042KbdDpcRoutine( 00314 IN PKDPC Dpc, 00315 IN PVOID DeferredContext, 00316 IN PVOID SystemArgument1, 00317 IN PVOID SystemArgument2) 00318 { 00319 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00320 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00321 ULONG KeysTransferred = 0; 00322 ULONG KeysInBufferCopy; 00323 KIRQL Irql; 00324 00325 UNREFERENCED_PARAMETER(Dpc); 00326 UNREFERENCED_PARAMETER(SystemArgument1); 00327 UNREFERENCED_PARAMETER(SystemArgument2); 00328 00329 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeferredContext; 00330 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00331 00332 if (HandlePowerKeys(DeviceExtension)) 00333 { 00334 DeviceExtension->KeyComplete = FALSE; 00335 return; 00336 } 00337 00338 i8042PacketDpc(PortDeviceExtension); 00339 if (!DeviceExtension->KeyComplete) 00340 return; 00341 /* We got the interrupt as it was being enabled, too bad */ 00342 if (!PortDeviceExtension->HighestDIRQLInterrupt) 00343 return; 00344 00345 Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt); 00346 00347 DeviceExtension->KeyComplete = FALSE; 00348 KeysInBufferCopy = DeviceExtension->KeysInBuffer; 00349 00350 KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql); 00351 00352 TRACE_(I8042PRT, "Send a key\n"); 00353 00354 if (!DeviceExtension->KeyboardData.ClassService) 00355 return; 00356 00357 INFO_(I8042PRT, "Sending %lu key(s)\n", KeysInBufferCopy); 00358 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->KeyboardData.ClassService)( 00359 DeviceExtension->KeyboardData.ClassDeviceObject, 00360 DeviceExtension->KeyboardBuffer, 00361 DeviceExtension->KeyboardBuffer + KeysInBufferCopy, 00362 &KeysTransferred); 00363 00364 KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt); 00365 DeviceExtension->KeysInBuffer -= KeysTransferred; 00366 KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql); 00367 } 00368 00369 /* 00370 * Runs the keyboard IOCTL dispatch. 00371 */ 00372 NTSTATUS NTAPI 00373 i8042KbdDeviceControl( 00374 IN PDEVICE_OBJECT DeviceObject, 00375 IN PIRP Irp) 00376 { 00377 PIO_STACK_LOCATION Stack; 00378 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00379 NTSTATUS Status; 00380 00381 Stack = IoGetCurrentIrpStackLocation(Irp); 00382 Irp->IoStatus.Information = 0; 00383 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension; 00384 00385 switch (Stack->Parameters.DeviceIoControl.IoControlCode) 00386 { 00387 case IOCTL_GET_SYS_BUTTON_CAPS: 00388 { 00389 /* Part of GUID_DEVICE_SYS_BUTTON interface */ 00390 PULONG pCaps; 00391 TRACE_(I8042PRT, "IOCTL_GET_SYS_BUTTON_CAPS\n"); 00392 00393 if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG)) 00394 Status = STATUS_INVALID_PARAMETER; 00395 else 00396 { 00397 pCaps = (PULONG)Irp->AssociatedIrp.SystemBuffer; 00398 *pCaps = DeviceExtension->NewCaps; 00399 DeviceExtension->ReportedCaps = DeviceExtension->NewCaps; 00400 Irp->IoStatus.Information = sizeof(ULONG); 00401 Status = STATUS_SUCCESS; 00402 } 00403 break; 00404 } 00405 case IOCTL_GET_SYS_BUTTON_EVENT: 00406 { 00407 /* Part of GUID_DEVICE_SYS_BUTTON interface */ 00408 PIRP WaitingIrp; 00409 TRACE_(I8042PRT, "IOCTL_GET_SYS_BUTTON_EVENT\n"); 00410 00411 if (Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG)) 00412 Status = STATUS_INVALID_PARAMETER; 00413 else 00414 { 00415 WaitingIrp = InterlockedCompareExchangePointer( 00416 (PVOID)&DeviceExtension->PowerIrp, 00417 Irp, 00418 NULL); 00419 /* Check if an Irp is already pending */ 00420 if (WaitingIrp) 00421 { 00422 /* Unable to have a 2nd pending IRP for this IOCTL */ 00423 WARN_(I8042PRT, "Unable to pend a second IRP for IOCTL_GET_SYS_BUTTON_EVENT\n"); 00424 Status = STATUS_INVALID_PARAMETER; 00425 Irp->IoStatus.Status = Status; 00426 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00427 } 00428 else 00429 { 00430 ULONG PowerKey; 00431 PowerKey = InterlockedExchange((PLONG)&DeviceExtension->LastPowerKey, 0); 00432 if (PowerKey != 0) 00433 { 00434 (VOID)InterlockedCompareExchangePointer((PVOID)&DeviceExtension->PowerIrp, NULL, Irp); 00435 *(PULONG)Irp->AssociatedIrp.SystemBuffer = PowerKey; 00436 Status = STATUS_SUCCESS; 00437 Irp->IoStatus.Status = Status; 00438 Irp->IoStatus.Information = sizeof(ULONG); 00439 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00440 } 00441 else 00442 { 00443 TRACE_(I8042PRT, "Pending IOCTL_GET_SYS_BUTTON_EVENT\n"); 00444 Status = STATUS_PENDING; 00445 Irp->IoStatus.Status = Status; 00446 IoMarkIrpPending(Irp); 00447 } 00448 } 00449 return Status; 00450 } 00451 break; 00452 } 00453 default: 00454 { 00455 ERR_(I8042PRT, "IRP_MJ_DEVICE_CONTROL / unknown ioctl code 0x%lx\n", 00456 Stack->Parameters.DeviceIoControl.IoControlCode); 00457 ASSERT(FALSE); 00458 return ForwardIrpAndForget(DeviceObject, Irp); 00459 } 00460 } 00461 00462 Irp->IoStatus.Status = Status; 00463 if (Status == STATUS_PENDING) 00464 IoMarkIrpPending(Irp); 00465 else 00466 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00467 00468 return Status; 00469 } 00470 00471 /* 00472 * Runs the keyboard IOCTL_INTERNAL dispatch. 00473 */ 00474 NTSTATUS NTAPI 00475 i8042KbdInternalDeviceControl( 00476 IN PDEVICE_OBJECT DeviceObject, 00477 IN PIRP Irp) 00478 { 00479 PIO_STACK_LOCATION Stack; 00480 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00481 NTSTATUS Status; 00482 00483 Stack = IoGetCurrentIrpStackLocation(Irp); 00484 Irp->IoStatus.Information = 0; 00485 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)DeviceObject->DeviceExtension; 00486 00487 switch (Stack->Parameters.DeviceIoControl.IoControlCode) 00488 { 00489 case IOCTL_INTERNAL_KEYBOARD_CONNECT: 00490 { 00491 SIZE_T Size; 00492 PIO_WORKITEM WorkItem = NULL; 00493 PI8042_HOOK_WORKITEM WorkItemData = NULL; 00494 00495 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_CONNECT\n"); 00496 if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA)) 00497 { 00498 Status = STATUS_INVALID_PARAMETER; 00499 goto cleanup; 00500 } 00501 00502 DeviceExtension->KeyboardData = 00503 *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer); 00504 00505 /* Send IOCTL_INTERNAL_I8042_HOOK_KEYBOARD to device stack */ 00506 WorkItem = IoAllocateWorkItem(DeviceObject); 00507 if (!WorkItem) 00508 { 00509 WARN_(I8042PRT, "IoAllocateWorkItem() failed\n"); 00510 Status = STATUS_INSUFFICIENT_RESOURCES; 00511 goto cleanup; 00512 } 00513 WorkItemData = ExAllocatePoolWithTag( 00514 NonPagedPool, 00515 sizeof(I8042_HOOK_WORKITEM), 00516 I8042PRT_TAG); 00517 if (!WorkItemData) 00518 { 00519 WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n"); 00520 Status = STATUS_NO_MEMORY; 00521 goto cleanup; 00522 } 00523 WorkItemData->WorkItem = WorkItem; 00524 WorkItemData->Irp = Irp; 00525 00526 /* Initialize extension */ 00527 DeviceExtension->Common.Type = Keyboard; 00528 Size = DeviceExtension->Common.PortDeviceExtension->Settings.KeyboardDataQueueSize * sizeof(KEYBOARD_INPUT_DATA); 00529 DeviceExtension->KeyboardBuffer = ExAllocatePoolWithTag( 00530 NonPagedPool, 00531 Size, 00532 I8042PRT_TAG); 00533 if (!DeviceExtension->KeyboardBuffer) 00534 { 00535 WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n"); 00536 Status = STATUS_NO_MEMORY; 00537 goto cleanup; 00538 } 00539 RtlZeroMemory(DeviceExtension->KeyboardBuffer, Size); 00540 KeInitializeDpc( 00541 &DeviceExtension->DpcKeyboard, 00542 i8042KbdDpcRoutine, 00543 DeviceExtension); 00544 DeviceExtension->PowerWorkItem = IoAllocateWorkItem(DeviceObject); 00545 if (!DeviceExtension->PowerWorkItem) 00546 { 00547 WARN_(I8042PRT, "IoAllocateWorkItem() failed\n"); 00548 Status = STATUS_INSUFFICIENT_RESOURCES; 00549 goto cleanup; 00550 } 00551 DeviceExtension->DebugWorkItem = IoAllocateWorkItem(DeviceObject); 00552 if (!DeviceExtension->DebugWorkItem) 00553 { 00554 WARN_(I8042PRT, "IoAllocateWorkItem() failed\n"); 00555 Status = STATUS_INSUFFICIENT_RESOURCES; 00556 goto cleanup; 00557 } 00558 DeviceExtension->Common.PortDeviceExtension->KeyboardExtension = DeviceExtension; 00559 DeviceExtension->Common.PortDeviceExtension->Flags |= KEYBOARD_CONNECTED; 00560 00561 IoMarkIrpPending(Irp); 00562 /* FIXME: DeviceExtension->KeyboardHook.IsrWritePort = ; */ 00563 DeviceExtension->KeyboardHook.QueueKeyboardPacket = i8042KbdQueuePacket; 00564 DeviceExtension->KeyboardHook.CallContext = DeviceExtension; 00565 IoQueueWorkItem(WorkItem, 00566 i8042SendHookWorkItem, 00567 DelayedWorkQueue, 00568 WorkItemData); 00569 Status = STATUS_PENDING; 00570 break; 00571 00572 cleanup: 00573 if (DeviceExtension->KeyboardBuffer) 00574 ExFreePoolWithTag(DeviceExtension->KeyboardBuffer, I8042PRT_TAG); 00575 if (DeviceExtension->PowerWorkItem) 00576 IoFreeWorkItem(DeviceExtension->PowerWorkItem); 00577 if (DeviceExtension->DebugWorkItem) 00578 IoFreeWorkItem(DeviceExtension->DebugWorkItem); 00579 if (WorkItem) 00580 IoFreeWorkItem(WorkItem); 00581 if (WorkItemData) 00582 ExFreePoolWithTag(WorkItemData, I8042PRT_TAG); 00583 break; 00584 } 00585 case IOCTL_INTERNAL_KEYBOARD_DISCONNECT: 00586 { 00587 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_KEYBOARD_DISCONNECT\n"); 00588 /* MSDN says that operation is to implemented. 00589 * To implement it, we just have to do: 00590 * DeviceExtension->KeyboardData.ClassService = NULL; 00591 */ 00592 Status = STATUS_NOT_IMPLEMENTED; 00593 break; 00594 } 00595 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD: 00596 { 00597 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_KEYBOARD\n"); 00598 /* Nothing to do here */ 00599 Status = STATUS_SUCCESS; 00600 break; 00601 } 00602 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES: 00603 { 00604 DPRINT1("IOCTL_KEYBOARD_QUERY_ATTRIBUTES not implemented\n"); 00605 #if 0 00606 /* FIXME: KeyboardAttributes are not initialized anywhere */ 00607 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n"); 00608 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_ATTRIBUTES)) 00609 { 00610 Status = STATUS_BUFFER_TOO_SMALL; 00611 break; 00612 } 00613 00614 *(PKEYBOARD_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = DeviceExtension->KeyboardAttributes; 00615 Irp->IoStatus.Information = sizeof(KEYBOARD_ATTRIBUTES); 00616 Status = STATUS_SUCCESS; 00617 break; 00618 #endif 00619 Status = STATUS_NOT_IMPLEMENTED; 00620 break; 00621 } 00622 case IOCTL_KEYBOARD_QUERY_TYPEMATIC: 00623 { 00624 DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n"); 00625 Status = STATUS_NOT_IMPLEMENTED; 00626 break; 00627 } 00628 case IOCTL_KEYBOARD_SET_TYPEMATIC: 00629 { 00630 DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n"); 00631 Status = STATUS_NOT_IMPLEMENTED; 00632 break; 00633 } 00634 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: 00635 { 00636 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n"); 00637 00638 /* We should check the UnitID, but it's kind of pointless as 00639 * all keyboards are supposed to have the same one 00640 */ 00641 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)) 00642 { 00643 Status = STATUS_BUFFER_TOO_SMALL; 00644 } 00645 else 00646 { 00647 RtlCopyMemory( 00648 Irp->AssociatedIrp.SystemBuffer, 00649 &IndicatorTranslation, 00650 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION)); 00651 Irp->IoStatus.Information = sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION); 00652 Status = STATUS_SUCCESS; 00653 } 00654 break; 00655 } 00656 case IOCTL_KEYBOARD_QUERY_INDICATORS: 00657 { 00658 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_QUERY_INDICATORS\n"); 00659 00660 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS)) 00661 { 00662 Status = STATUS_BUFFER_TOO_SMALL; 00663 } 00664 else 00665 { 00666 RtlCopyMemory( 00667 Irp->AssociatedIrp.SystemBuffer, 00668 &DeviceExtension->KeyboardIndicators, 00669 sizeof(KEYBOARD_INDICATOR_PARAMETERS)); 00670 Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS); 00671 Status = STATUS_SUCCESS; 00672 } 00673 break; 00674 } 00675 case IOCTL_KEYBOARD_SET_INDICATORS: 00676 { 00677 TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_KEYBOARD_SET_INDICATORS\n"); 00678 00679 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS)) 00680 { 00681 Status = STATUS_BUFFER_TOO_SMALL; 00682 } 00683 else 00684 { 00685 RtlCopyMemory( 00686 &DeviceExtension->KeyboardIndicators, 00687 Irp->AssociatedIrp.SystemBuffer, 00688 sizeof(KEYBOARD_INDICATOR_PARAMETERS)); 00689 Status = STATUS_PENDING; 00690 IoMarkIrpPending(Irp); 00691 IoStartPacket(DeviceObject, Irp, NULL, NULL); 00692 } 00693 break; 00694 } 00695 default: 00696 { 00697 ERR_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n", 00698 Stack->Parameters.DeviceIoControl.IoControlCode); 00699 ASSERT(FALSE); 00700 return ForwardIrpAndForget(DeviceObject, Irp); 00701 } 00702 } 00703 00704 Irp->IoStatus.Status = Status; 00705 if (Status != STATUS_PENDING) 00706 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00707 return Status; 00708 } 00709 00710 /* 00711 * Call the customization hook. The ToReturn parameter is about wether 00712 * we should go on with the interrupt. The return value is what 00713 * we should return (indicating to the system wether someone else 00714 * should try to handle the interrupt) 00715 */ 00716 static BOOLEAN 00717 i8042KbdCallIsrHook( 00718 IN PI8042_KEYBOARD_EXTENSION DeviceExtension, 00719 IN UCHAR Status, 00720 IN UCHAR Input, 00721 OUT PBOOLEAN ToReturn) 00722 { 00723 BOOLEAN HookReturn, HookContinue; 00724 00725 HookContinue = FALSE; 00726 00727 if (DeviceExtension->KeyboardHook.IsrRoutine) 00728 { 00729 HookReturn = DeviceExtension->KeyboardHook.IsrRoutine( 00730 DeviceExtension->KeyboardHook.Context, 00731 DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer, 00732 &DeviceExtension->Common.PortDeviceExtension->Packet, 00733 Status, 00734 &Input, 00735 &HookContinue, 00736 &DeviceExtension->KeyboardScanState); 00737 00738 if (!HookContinue) 00739 { 00740 *ToReturn = HookReturn; 00741 return TRUE; 00742 } 00743 } 00744 return FALSE; 00745 } 00746 00747 BOOLEAN NTAPI 00748 i8042KbdInterruptService( 00749 IN PKINTERRUPT Interrupt, 00750 PVOID Context) 00751 { 00752 PI8042_KEYBOARD_EXTENSION DeviceExtension; 00753 PPORT_DEVICE_EXTENSION PortDeviceExtension; 00754 PKEYBOARD_INPUT_DATA InputData; 00755 ULONG Counter; 00756 UCHAR PortStatus = 0, Output = 0; 00757 BOOLEAN ToReturn = FALSE; 00758 NTSTATUS Status; 00759 00760 UNREFERENCED_PARAMETER(Interrupt); 00761 00762 DeviceExtension = (PI8042_KEYBOARD_EXTENSION)Context; 00763 PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension; 00764 InputData = DeviceExtension->KeyboardBuffer + DeviceExtension->KeysInBuffer; 00765 Counter = PortDeviceExtension->Settings.PollStatusIterations; 00766 00767 while (Counter) 00768 { 00769 Status = i8042ReadStatus(PortDeviceExtension, &PortStatus); 00770 if (!NT_SUCCESS(Status)) 00771 { 00772 WARN_(I8042PRT, "i8042ReadStatus() failed with status 0x%08lx\n", Status); 00773 return FALSE; 00774 } 00775 Status = i8042ReadKeyboardData(PortDeviceExtension, &Output); 00776 if (NT_SUCCESS(Status)) 00777 break; 00778 KeStallExecutionProcessor(1); 00779 Counter--; 00780 } 00781 if (Counter == 0) 00782 { 00783 WARN_(I8042PRT, "Spurious i8042 keyboard interrupt\n"); 00784 return FALSE; 00785 } 00786 00787 INFO_(I8042PRT, "Got: 0x%02x\n", Output); 00788 00789 if (PortDeviceExtension->Settings.CrashOnCtrlScroll) 00790 { 00791 /* Test for CTRL + SCROLL LOCK twice */ 00792 static const UCHAR ScanCodes[] = { 0x1d, 0x46, 0xc6, 0x46, 0 }; 00793 00794 if (Output == ScanCodes[DeviceExtension->ComboPosition]) 00795 { 00796 DeviceExtension->ComboPosition++; 00797 if (ScanCodes[DeviceExtension->ComboPosition] == 0) 00798 KeBugCheck(MANUALLY_INITIATED_CRASH); 00799 } 00800 else if (Output == 0xfa) 00801 { 00802 /* Ignore ACK */ 00803 } 00804 else if (Output == ScanCodes[0]) 00805 DeviceExtension->ComboPosition = 1; 00806 else 00807 DeviceExtension->ComboPosition = 0; 00808 00809 /* Test for TAB + key combination */ 00810 if (InputData->MakeCode == 0x0F) 00811 DeviceExtension->TabPressed = !(InputData->Flags & KEY_BREAK); 00812 else if (DeviceExtension->TabPressed) 00813 { 00814 DeviceExtension->TabPressed = FALSE; 00815 00816 /* Check which action to do */ 00817 if (InputData->MakeCode == 0x25) 00818 { 00819 /* k - Breakpoint */ 00820 DbgBreakPoint(); 00821 } 00822 else if (InputData->MakeCode == 0x30) 00823 { 00824 /* b - Bugcheck */ 00825 KeBugCheck(MANUALLY_INITIATED_CRASH); 00826 } 00827 else 00828 { 00829 /* Send request to the kernel debugger. 00830 * Unknown requests will be ignored. */ 00831 KdSystemDebugControl(' soR', 00832 (PVOID)(ULONG_PTR)InputData->MakeCode, 00833 0, 00834 NULL, 00835 0, 00836 NULL, 00837 KernelMode); 00838 } 00839 } 00840 } 00841 00842 if (i8042KbdCallIsrHook(DeviceExtension, PortStatus, Output, &ToReturn)) 00843 return ToReturn; 00844 00845 if (i8042PacketIsr(PortDeviceExtension, Output)) 00846 { 00847 if (PortDeviceExtension->PacketComplete) 00848 { 00849 TRACE_(I8042PRT, "Packet complete\n"); 00850 KeInsertQueueDpc(&DeviceExtension->DpcKeyboard, NULL, NULL); 00851 } 00852 TRACE_(I8042PRT, "Irq eaten by packet\n"); 00853 return TRUE; 00854 } 00855 00856 TRACE_(I8042PRT, "Irq is keyboard input\n"); 00857 00858 if (DeviceExtension->KeyboardScanState == Normal) 00859 { 00860 switch (Output) 00861 { 00862 case 0xe0: 00863 DeviceExtension->KeyboardScanState = GotE0; 00864 return TRUE; 00865 case 0xe1: 00866 DeviceExtension->KeyboardScanState = GotE1; 00867 return TRUE; 00868 default: 00869 break; 00870 } 00871 } 00872 00873 /* Update InputData */ 00874 InputData->Flags = 0; 00875 switch (DeviceExtension->KeyboardScanState) 00876 { 00877 case GotE0: 00878 InputData->Flags |= KEY_E0; 00879 break; 00880 case GotE1: 00881 InputData->Flags |= KEY_E1; 00882 break; 00883 default: 00884 break; 00885 } 00886 DeviceExtension->KeyboardScanState = Normal; 00887 if (Output & 0x80) 00888 InputData->Flags |= KEY_BREAK; 00889 else 00890 InputData->Flags |= KEY_MAKE; 00891 InputData->MakeCode = Output & 0x7f; 00892 InputData->Reserved = 0; 00893 00894 DeviceExtension->KeyboardHook.QueueKeyboardPacket(DeviceExtension->KeyboardHook.CallContext); 00895 00896 return TRUE; 00897 } Generated on Fri May 25 2012 04:17:05 for ReactOS by
1.7.6.1
|