ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

keyboard.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.