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

mouse.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/mouse.c
00005  * PURPOSE:     Mouse 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                 Copyright 2008 Colin Finck (mail@colinfinck.de)
00011  */
00012 
00013 /* INCLUDES ****************************************************************/
00014 
00015 #include "i8042prt.h"
00016 
00017 /* FUNCTIONS *****************************************************************/
00018 
00019 /*
00020  * These functions are callbacks for filter driver custom interrupt
00021  * service routines.
00022  */
00023 static VOID NTAPI
00024 i8042MouIsrWritePort(
00025     IN PVOID Context,
00026     IN UCHAR Value)
00027 {
00028     PI8042_MOUSE_EXTENSION DeviceExtension;
00029 
00030     DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
00031 
00032     if (DeviceExtension->MouseHook.IsrWritePort != i8042MouIsrWritePort)
00033     {
00034         DeviceExtension->MouseHook.IsrWritePort(
00035             DeviceExtension->MouseHook.CallContext,
00036             Value);
00037     }
00038     else
00039         i8042IsrWritePort(DeviceExtension->Common.PortDeviceExtension, Value, CTRL_WRITE_MOUSE);
00040 }
00041 
00042 static VOID NTAPI
00043 i8042MouQueuePacket(
00044     IN PVOID Context)
00045 {
00046     PI8042_MOUSE_EXTENSION DeviceExtension;
00047 
00048     DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
00049 
00050     DeviceExtension->MouseComplete = TRUE;
00051     DeviceExtension->MouseInBuffer++;
00052     if (DeviceExtension->MouseInBuffer >= DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize)
00053     {
00054         WARN_(I8042PRT, "Mouse buffer overflow\n");
00055         DeviceExtension->MouseInBuffer--;
00056     }
00057 
00058     TRACE_(I8042PRT, "Irq completes mouse packet\n");
00059     KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
00060 }
00061 
00062 VOID
00063 i8042MouHandle(
00064     IN PI8042_MOUSE_EXTENSION DeviceExtension,
00065     IN UCHAR Output)
00066 {
00067     PMOUSE_INPUT_DATA MouseInput;
00068     CHAR Scroll;
00069 
00070     MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
00071 
00072     switch (DeviceExtension->MouseState)
00073     {
00074         case MouseIdle:
00075             /* This bit should be 1, if not drop the packet, we
00076              * might be lucky and get in sync again
00077              */
00078             if (!(Output & 8)) {
00079                 WARN_(I8042PRT, "Bad input, dropping..\n");
00080                 return;
00081             }
00082 
00083             MouseInput->Buttons = 0;
00084             MouseInput->RawButtons = 0;
00085             MouseInput->Flags = MOUSE_MOVE_RELATIVE;
00086 
00087             /* Note how we ignore the overflow bits, like Windows
00088              * is said to do. There's no reasonable thing to do
00089              * anyway.
00090              */
00091 
00092             if (Output & 16)
00093                 MouseInput->LastX = 1;
00094             else
00095                 MouseInput->LastX = 0;
00096             if (Output & 32)
00097                 MouseInput->LastY = 1;
00098             else
00099                 MouseInput->LastY = 0;
00100 
00101             if (Output & 1)
00102                 MouseInput->RawButtons |= MOUSE_LEFT_BUTTON_DOWN;
00103             if (Output & 2)
00104                 MouseInput->RawButtons |= MOUSE_RIGHT_BUTTON_DOWN;
00105             if (Output & 4)
00106                 MouseInput->RawButtons |= MOUSE_MIDDLE_BUTTON_DOWN;
00107 
00108             DeviceExtension->MouseState = XMovement;
00109             break;
00110 
00111         case XMovement:
00112             if (MouseInput->LastX)
00113                 MouseInput->LastX = (LONG) Output - 256;
00114             else
00115                 MouseInput->LastX = Output;
00116 
00117             DeviceExtension->MouseState = YMovement;
00118             break;
00119 
00120         case YMovement:
00121             if (MouseInput->LastY)
00122                 MouseInput->LastY = (LONG)Output - 256;
00123             else
00124                 MouseInput->LastY = (LONG)Output;
00125 
00126             /* Windows wants it the other way around */
00127             MouseInput->LastY = -MouseInput->LastY;
00128 
00129             if (DeviceExtension->MouseType == GenericPS2 ||
00130                 DeviceExtension->MouseType == Ps2pp)
00131             {
00132                 i8042MouHandleButtons(
00133                     DeviceExtension,
00134                     MOUSE_LEFT_BUTTON_DOWN |
00135                     MOUSE_RIGHT_BUTTON_DOWN |
00136                     MOUSE_MIDDLE_BUTTON_DOWN);
00137                 DeviceExtension->MouseHook.QueueMousePacket(DeviceExtension->MouseHook.CallContext);
00138                 DeviceExtension->MouseState = MouseIdle;
00139             }
00140             else
00141             {
00142                 DeviceExtension->MouseState = ZMovement;
00143             }
00144             break;
00145 
00146         case ZMovement:
00147             Scroll = Output & 0x0f;
00148             if (Scroll & 8)
00149                 Scroll |= 0xf0;
00150 
00151             if (Scroll)
00152             {
00153                 MouseInput->RawButtons |= MOUSE_WHEEL;
00154                 MouseInput->ButtonData = (USHORT)(Scroll * -WHEEL_DELTA);
00155             }
00156 
00157             if (DeviceExtension->MouseType == IntellimouseExplorer)
00158             {
00159                 if (Output & 16)
00160                     MouseInput->RawButtons |= MOUSE_BUTTON_4_DOWN;
00161                 if (Output & 32)
00162                     MouseInput->RawButtons |= MOUSE_BUTTON_5_DOWN;
00163             }
00164             i8042MouHandleButtons(
00165                 DeviceExtension,
00166                 MOUSE_LEFT_BUTTON_DOWN |
00167                 MOUSE_RIGHT_BUTTON_DOWN |
00168                 MOUSE_MIDDLE_BUTTON_DOWN |
00169                 MOUSE_BUTTON_4_DOWN |
00170                 MOUSE_BUTTON_5_DOWN);
00171             DeviceExtension->MouseHook.QueueMousePacket(DeviceExtension->MouseHook.CallContext);
00172             DeviceExtension->MouseState = MouseIdle;
00173             break;
00174 
00175         default:
00176             ERR_(I8042PRT, "Unexpected state 0x%u!\n", DeviceExtension->MouseState);
00177             ASSERT(FALSE);
00178     }
00179 }
00180 
00181 /*
00182  * Updates ButtonFlags according to RawButtons and a saved state;
00183  * Only takes in account the bits that are set in Mask
00184  */
00185 VOID
00186 i8042MouHandleButtons(
00187     IN PI8042_MOUSE_EXTENSION DeviceExtension,
00188     IN USHORT Mask)
00189 {
00190     PMOUSE_INPUT_DATA MouseInput;
00191     USHORT NewButtonData;
00192     USHORT ButtonDiff;
00193 
00194     MouseInput = DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer;
00195     NewButtonData = (USHORT)(MouseInput->RawButtons & Mask);
00196     ButtonDiff = (NewButtonData ^ DeviceExtension->MouseButtonState) & Mask;
00197 
00198     /* Note that the defines are such:
00199      * MOUSE_LEFT_BUTTON_DOWN 1
00200      * MOUSE_LEFT_BUTTON_UP   2
00201      */
00202     MouseInput->ButtonFlags |= (NewButtonData & ButtonDiff) |
00203         (((~(NewButtonData)) << 1) & (ButtonDiff << 1)) |
00204         (MouseInput->RawButtons & 0xfc00);
00205 
00206     INFO_(I8042PRT, "Left raw/up/down: %u/%u/%u\n",
00207         MouseInput->RawButtons & MOUSE_LEFT_BUTTON_DOWN,
00208         MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN,
00209         MouseInput->ButtonFlags & MOUSE_LEFT_BUTTON_UP);
00210 
00211     DeviceExtension->MouseButtonState =
00212         (DeviceExtension->MouseButtonState & ~Mask) | (NewButtonData & Mask);
00213 }
00214 
00215 /* Does lastest initializations for the mouse. This method
00216  * is called just before connecting the interrupt.
00217  */
00218 NTSTATUS
00219 i8042MouInitialize(
00220     IN PI8042_MOUSE_EXTENSION DeviceExtension)
00221 {
00222     NTSTATUS Status;
00223     UCHAR Value;
00224 
00225     /* Enable the PS/2 mouse port */
00226     i8042Write(DeviceExtension->Common.PortDeviceExtension, DeviceExtension->Common.PortDeviceExtension->ControlPort, MOUSE_ENAB);
00227 
00228     /* Enable the mouse */
00229     if(!i8042IsrWritePort(DeviceExtension->Common.PortDeviceExtension, MOU_ENAB, CTRL_WRITE_MOUSE))
00230     {
00231         WARN_(I8042PRT, "Failed to enable mouse!\n");
00232         return STATUS_IO_DEVICE_ERROR;
00233     }
00234 
00235     Status = i8042ReadDataWait(DeviceExtension->Common.PortDeviceExtension, &Value);
00236     if (!NT_SUCCESS(Status))
00237     {
00238         WARN_(I8042PRT, "Failed to read the response of MOU_ENAB, status 0x%08lx\n", Status);
00239         return Status;
00240     }
00241 
00242     if(Value == MOUSE_ACK)
00243     {
00244         INFO_(I8042PRT, "Mouse was enabled successfully!\n");
00245         return STATUS_SUCCESS;
00246     }
00247 
00248     WARN_(I8042PRT, "Got 0x%02x instead of 0xFA\n", Value);
00249     return STATUS_IO_DEVICE_ERROR;
00250 }
00251 
00252 static VOID NTAPI
00253 i8042MouDpcRoutine(
00254     IN PKDPC Dpc,
00255     IN PVOID DeferredContext,
00256     IN PVOID SystemArgument1,
00257     IN PVOID SystemArgument2)
00258 {
00259     PI8042_MOUSE_EXTENSION DeviceExtension;
00260     PPORT_DEVICE_EXTENSION PortDeviceExtension;
00261     ULONG MouseTransferred = 0;
00262     ULONG MouseInBufferCopy;
00263     KIRQL Irql;
00264     LARGE_INTEGER Timeout;
00265 
00266     UNREFERENCED_PARAMETER(Dpc);
00267     UNREFERENCED_PARAMETER(SystemArgument1);
00268     UNREFERENCED_PARAMETER(SystemArgument2);
00269 
00270     DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext;
00271     PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
00272 
00273     switch (DeviceExtension->MouseTimeoutState)
00274     {
00275         case TimeoutStart:
00276         {
00277             DeviceExtension->MouseTimeoutState = NoChange;
00278             if (DeviceExtension->MouseTimeoutActive &&
00279                 !KeCancelTimer(&DeviceExtension->TimerMouseTimeout))
00280             {
00281                 /* The timer fired already, give up */
00282                 DeviceExtension->MouseTimeoutActive = FALSE;
00283                 return;
00284             }
00285 
00286             Timeout.QuadPart = -15000000; /* 1.5 seconds, should be enough */
00287 
00288             KeSetTimer(
00289                 &DeviceExtension->TimerMouseTimeout,
00290                 Timeout,
00291                 &DeviceExtension->DpcMouseTimeout);
00292             DeviceExtension->MouseTimeoutActive = TRUE;
00293             return;
00294         }
00295 
00296         case TimeoutCancel:
00297         {
00298             DeviceExtension->MouseTimeoutState = NoChange;
00299             KeCancelTimer(&DeviceExtension->TimerMouseTimeout);
00300             DeviceExtension->MouseTimeoutActive = FALSE;
00301         }
00302 
00303         default:
00304             ;/* nothing, don't want a warning */
00305     }
00306 
00307     /* Should be unlikely */
00308     if (!DeviceExtension->MouseComplete)
00309         return;
00310 
00311     Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
00312 
00313     DeviceExtension->MouseComplete = FALSE;
00314     MouseInBufferCopy = DeviceExtension->MouseInBuffer;
00315 
00316     KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
00317 
00318     TRACE_(I8042PRT, "Send a mouse packet\n");
00319 
00320     if (!DeviceExtension->MouseData.ClassService)
00321         return;
00322 
00323     INFO_(I8042PRT, "Sending %lu mouse move(s)\n", MouseInBufferCopy);
00324     (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->MouseData.ClassService)(
00325         DeviceExtension->MouseData.ClassDeviceObject,
00326         DeviceExtension->MouseBuffer,
00327         DeviceExtension->MouseBuffer + MouseInBufferCopy,
00328         &MouseTransferred);
00329 
00330     Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
00331     DeviceExtension->MouseInBuffer -= MouseTransferred;
00332     if (DeviceExtension->MouseInBuffer)
00333         RtlMoveMemory(
00334             DeviceExtension->MouseBuffer,
00335             DeviceExtension->MouseBuffer + MouseTransferred,
00336             DeviceExtension->MouseInBuffer * sizeof(MOUSE_INPUT_DATA));
00337     KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
00338 }
00339 
00340 /* This timer DPC will be called when the mouse reset times out.
00341  * I'll just send the 'disable mouse port' command to the controller
00342  * and say the mouse doesn't exist.
00343  */
00344 static VOID NTAPI
00345 i8042DpcRoutineMouseTimeout(
00346     IN PKDPC Dpc,
00347     IN PVOID DeferredContext,
00348     IN PVOID SystemArgument1,
00349     IN PVOID SystemArgument2)
00350 {
00351     PI8042_MOUSE_EXTENSION DeviceExtension;
00352     PPORT_DEVICE_EXTENSION PortDeviceExtension;
00353     KIRQL Irql;
00354 
00355     UNREFERENCED_PARAMETER(Dpc);
00356     UNREFERENCED_PARAMETER(SystemArgument1);
00357     UNREFERENCED_PARAMETER(SystemArgument2);
00358 
00359     DeviceExtension = (PI8042_MOUSE_EXTENSION)DeferredContext;
00360     PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
00361 
00362     Irql = KeAcquireInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt);
00363 
00364     WARN_(I8042PRT, "Mouse initialization timeout! (substate %x)\n",
00365         DeviceExtension->MouseResetState);
00366 
00367     PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
00368 
00369     KeReleaseInterruptSpinLock(PortDeviceExtension->HighestDIRQLInterrupt, Irql);
00370 }
00371 
00372 /*
00373  * Runs the mouse IOCTL_INTERNAL dispatch.
00374  */
00375 NTSTATUS NTAPI
00376 i8042MouInternalDeviceControl(
00377     IN PDEVICE_OBJECT DeviceObject,
00378     IN PIRP Irp)
00379 {
00380     PIO_STACK_LOCATION Stack;
00381     PI8042_MOUSE_EXTENSION DeviceExtension;
00382     NTSTATUS Status;
00383 
00384     Stack = IoGetCurrentIrpStackLocation(Irp);
00385     Irp->IoStatus.Information = 0;
00386     DeviceExtension = (PI8042_MOUSE_EXTENSION)DeviceObject->DeviceExtension;
00387 
00388     switch (Stack->Parameters.DeviceIoControl.IoControlCode)
00389     {
00390         case IOCTL_INTERNAL_MOUSE_CONNECT:
00391         {
00392             SIZE_T Size;
00393             PIO_WORKITEM WorkItem = NULL;
00394             PI8042_HOOK_WORKITEM WorkItemData = NULL;
00395 
00396             TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_CONNECT\n");
00397             if (Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(CONNECT_DATA))
00398             {
00399                 Status = STATUS_INVALID_PARAMETER;
00400                 goto cleanup;
00401             }
00402 
00403             DeviceExtension->MouseData =
00404                 *((PCONNECT_DATA)Stack->Parameters.DeviceIoControl.Type3InputBuffer);
00405 
00406             /* Send IOCTL_INTERNAL_I8042_HOOK_MOUSE to device stack */
00407             WorkItem = IoAllocateWorkItem(DeviceObject);
00408             if (!WorkItem)
00409             {
00410                 WARN_(I8042PRT, "IoAllocateWorkItem() failed\n");
00411                 Status = STATUS_INSUFFICIENT_RESOURCES;
00412                 goto cleanup;
00413             }
00414             WorkItemData = ExAllocatePoolWithTag(
00415                 NonPagedPool,
00416                 sizeof(I8042_HOOK_WORKITEM),
00417                 I8042PRT_TAG);
00418             if (!WorkItemData)
00419             {
00420                 WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n");
00421                 Status = STATUS_NO_MEMORY;
00422                 goto cleanup;
00423             }
00424             WorkItemData->WorkItem = WorkItem;
00425             WorkItemData->Irp = Irp;
00426 
00427             /* Initialize extension */
00428             DeviceExtension->Common.Type = Mouse;
00429             Size = DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize * sizeof(MOUSE_INPUT_DATA);
00430             DeviceExtension->MouseBuffer = ExAllocatePoolWithTag(
00431                 NonPagedPool,
00432                 Size,
00433                 I8042PRT_TAG);
00434             if (!DeviceExtension->MouseBuffer)
00435             {
00436                 WARN_(I8042PRT, "ExAllocatePoolWithTag() failed\n");
00437                 Status = STATUS_NO_MEMORY;
00438                 goto cleanup;
00439             }
00440             RtlZeroMemory(DeviceExtension->MouseBuffer, Size);
00441             DeviceExtension->MouseAttributes.InputDataQueueLength =
00442                 DeviceExtension->Common.PortDeviceExtension->Settings.MouseDataQueueSize;
00443             KeInitializeDpc(
00444                 &DeviceExtension->DpcMouse,
00445                 i8042MouDpcRoutine,
00446                 DeviceExtension);
00447             KeInitializeDpc(
00448                 &DeviceExtension->DpcMouseTimeout,
00449                 i8042DpcRoutineMouseTimeout,
00450                 DeviceExtension);
00451             KeInitializeTimer(&DeviceExtension->TimerMouseTimeout);
00452             DeviceExtension->Common.PortDeviceExtension->MouseExtension = DeviceExtension;
00453             DeviceExtension->Common.PortDeviceExtension->Flags |= MOUSE_CONNECTED;
00454 
00455             IoMarkIrpPending(Irp);
00456             DeviceExtension->MouseState = MouseResetting;
00457             DeviceExtension->MouseResetState = ExpectingReset;
00458             DeviceExtension->MouseHook.IsrWritePort = i8042MouIsrWritePort;
00459             DeviceExtension->MouseHook.QueueMousePacket = i8042MouQueuePacket;
00460             DeviceExtension->MouseHook.CallContext = DeviceExtension;
00461             IoQueueWorkItem(WorkItem,
00462                 i8042SendHookWorkItem,
00463                 DelayedWorkQueue,
00464                 WorkItemData);
00465             Status = STATUS_PENDING;
00466             break;
00467 
00468 cleanup:
00469             if (DeviceExtension->MouseBuffer)
00470                 ExFreePoolWithTag(DeviceExtension->MouseBuffer, I8042PRT_TAG);
00471             if (WorkItem)
00472                 IoFreeWorkItem(WorkItem);
00473             if (WorkItemData)
00474                 ExFreePoolWithTag(WorkItemData, I8042PRT_TAG);
00475             break;
00476         }
00477         case IOCTL_INTERNAL_MOUSE_DISCONNECT:
00478         {
00479             TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_MOUSE_DISCONNECT\n");
00480             /* MSDN says that operation is to implemented.
00481              * To implement it, we just have to do:
00482              * DeviceExtension->MouseData.ClassService = NULL;
00483              */
00484             Status = STATUS_NOT_IMPLEMENTED;
00485             break;
00486         }
00487         case IOCTL_INTERNAL_I8042_HOOK_MOUSE:
00488         {
00489             PINTERNAL_I8042_HOOK_MOUSE MouseHook;
00490             TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_INTERNAL_I8042_HOOK_MOUSE\n");
00491             if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(INTERNAL_I8042_HOOK_MOUSE))
00492             {
00493                 Status = STATUS_INVALID_PARAMETER;
00494                 break;
00495             }
00496             MouseHook = (PINTERNAL_I8042_HOOK_MOUSE)Stack->Parameters.DeviceIoControl.Type3InputBuffer;
00497 
00498             DeviceExtension->MouseHook.Context = MouseHook->Context;
00499             if (MouseHook->IsrRoutine)
00500                 DeviceExtension->MouseHook.IsrRoutine = MouseHook->IsrRoutine;
00501 
00502             Status = STATUS_SUCCESS;
00503             break;
00504         }
00505         case IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER:
00506         {
00507             DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER not implemented\n");
00508             Status = STATUS_NOT_IMPLEMENTED;
00509             break;
00510         }
00511         case IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION:
00512         {
00513             DPRINT1("IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION not implemented\n");
00514             Status = STATUS_NOT_IMPLEMENTED;
00515             break;
00516         }
00517         case IOCTL_MOUSE_QUERY_ATTRIBUTES:
00518         {
00519             TRACE_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / IOCTL_MOUSE_QUERY_ATTRIBUTES\n");
00520             if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
00521             {
00522                 Status = STATUS_BUFFER_TOO_SMALL;
00523                 break;
00524             }
00525 
00526             *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer = DeviceExtension->MouseAttributes;
00527             Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
00528             Status = STATUS_SUCCESS;
00529             break;
00530         }
00531         default:
00532         {
00533             ERR_(I8042PRT, "IRP_MJ_INTERNAL_DEVICE_CONTROL / unknown ioctl code 0x%lx\n",
00534                 Stack->Parameters.DeviceIoControl.IoControlCode);
00535             ASSERT(FALSE);
00536             return ForwardIrpAndForget(DeviceObject, Irp);
00537         }
00538     }
00539 
00540     Irp->IoStatus.Status = Status;
00541     if (Status != STATUS_PENDING)
00542         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00543     return Status;
00544 }
00545 
00546 /* Test if packets are taking too long to come in. If they do, we
00547  * might have gotten out of sync and should just drop what we have.
00548  *
00549  * If we want to be totally right, we'd also have to keep a count of
00550  * errors, and totally reset the mouse after too much of them (can
00551  * happen if the user is using a KVM switch and an OS on another port
00552  * resets the mouse, or if the user hotplugs the mouse, or if we're just
00553  * generally unlucky). Also note the input parsing routine where we
00554  * drop invalid input packets.
00555  */
00556 static VOID
00557 i8042MouInputTestTimeout(
00558     IN PI8042_MOUSE_EXTENSION DeviceExtension)
00559 {
00560     ULARGE_INTEGER Now;
00561 
00562     if (DeviceExtension->MouseState == MouseExpectingACK ||
00563         DeviceExtension->MouseState == MouseResetting)
00564         return;
00565 
00566     Now.QuadPart = KeQueryInterruptTime();
00567 
00568     if (DeviceExtension->MouseState != MouseIdle) {
00569         /* Check if the last byte came too long ago */
00570         if (Now.QuadPart - DeviceExtension->MousePacketStartTime.QuadPart >
00571             DeviceExtension->Common.PortDeviceExtension->Settings.MouseSynchIn100ns)
00572         {
00573             WARN_(I8042PRT, "Mouse input packet timeout\n");
00574             DeviceExtension->MouseState = MouseIdle;
00575         }
00576     }
00577 
00578     if (DeviceExtension->MouseState == MouseIdle)
00579         DeviceExtension->MousePacketStartTime.QuadPart = Now.QuadPart;
00580 }
00581 
00582 /*
00583  * Call the customization hook. The ToReturn parameter is about wether
00584  * we should go on with the interrupt. The return value is what
00585  * we should return (indicating to the system wether someone else
00586  * should try to handle the interrupt)
00587  */
00588 static BOOLEAN
00589 i8042MouCallIsrHook(
00590     IN PI8042_MOUSE_EXTENSION DeviceExtension,
00591     IN UCHAR Status,
00592     IN UCHAR Input,
00593     OUT PBOOLEAN ToReturn)
00594 {
00595     BOOLEAN HookReturn, HookContinue;
00596 
00597     HookContinue = FALSE;
00598 
00599     if (DeviceExtension->MouseHook.IsrRoutine)
00600     {
00601         HookReturn = DeviceExtension->MouseHook.IsrRoutine(
00602             DeviceExtension->MouseHook.Context,
00603             DeviceExtension->MouseBuffer + DeviceExtension->MouseInBuffer,
00604             &DeviceExtension->Common.PortDeviceExtension->Packet,
00605             Status,
00606             &Input,
00607             &HookContinue,
00608             &DeviceExtension->MouseState,
00609             &DeviceExtension->MouseResetState);
00610 
00611         if (!HookContinue)
00612         {
00613             *ToReturn = HookReturn;
00614             return TRUE;
00615         }
00616     }
00617     return FALSE;
00618 }
00619 
00620 static BOOLEAN
00621 i8042MouResetIsr(
00622     IN PI8042_MOUSE_EXTENSION DeviceExtension,
00623     IN UCHAR Status,
00624     IN UCHAR Value)
00625 {
00626     PPORT_DEVICE_EXTENSION PortDeviceExtension;
00627     BOOLEAN ToReturn = FALSE;
00628 
00629     if (i8042MouCallIsrHook(DeviceExtension, Status, Value, &ToReturn))
00630         return ToReturn;
00631 
00632     if (MouseIdle == DeviceExtension->MouseState)
00633     {
00634         /* Magic packet value that indicates a reset */
00635         if (0xAA == Value)
00636         {
00637             WARN_(I8042PRT, "Hot plugged mouse!\n");
00638             DeviceExtension->MouseState = MouseResetting;
00639             DeviceExtension->MouseResetState = ExpectingReset;
00640         }
00641         else
00642             return FALSE;
00643     }
00644     else if (MouseResetting != DeviceExtension->MouseState)
00645         return FALSE;
00646 
00647     DeviceExtension->MouseTimeoutState = TimeoutStart;
00648     PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
00649 
00650     switch ((ULONG)DeviceExtension->MouseResetState)
00651     {
00652         case ExpectingReset:
00653             if (MOUSE_ACK == Value)
00654             {
00655                 WARN_(I8042PRT, "Dropping extra ACK\n");
00656                 return TRUE;
00657             }
00658 
00659             /* First, 0xFF is sent. The mouse is supposed to say AA00 if ok, FC00 if not. */
00660             if (0xAA == Value)
00661             {
00662                 DeviceExtension->MouseResetState++;
00663             }
00664             else
00665             {
00666                 PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
00667                 DeviceExtension->MouseState = MouseIdle;
00668                 WARN_(I8042PRT, "Mouse returned bad reset reply: %x (expected aa)\n", Value);
00669             }
00670             return TRUE;
00671         case ExpectingResetId:
00672             if (MOUSE_ACK == Value)
00673             {
00674                 WARN_(I8042PRT, "Dropping extra ACK #2\n");
00675                 return TRUE;
00676             }
00677 
00678             if (0x00 == Value)
00679             {
00680                 DeviceExtension->MouseResetState++;
00681                 DeviceExtension->MouseType = GenericPS2;
00682                 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2);
00683             }
00684             else
00685             {
00686                 PortDeviceExtension->Flags &= ~MOUSE_PRESENT;
00687                 DeviceExtension->MouseState = MouseIdle;
00688                 WARN_(I8042PRT, "Mouse returned bad reset reply part two: %x (expected 0)\n", Value);
00689             }
00690             return TRUE;
00691         case ExpectingGetDeviceIdACK:
00692             if (MOUSE_ACK == Value)
00693             {
00694                 DeviceExtension->MouseResetState++;
00695             }
00696             else if (MOUSE_NACK == Value || MOUSE_ERROR == Value)
00697             {
00698                 DeviceExtension->MouseResetState++;
00699                 /* Act as if 00 (normal mouse) was received */
00700                 WARN_(I8042PRT, "Mouse doesn't support 0xd2, (returns %x, expected %x), faking\n", Value, MOUSE_ACK);
00701                 i8042MouResetIsr(DeviceExtension, Status, 0);
00702             }
00703             return TRUE;
00704         case ExpectingGetDeviceIdValue:
00705             switch (Value)
00706             {
00707                 case 0x02:
00708                     DeviceExtension->MouseAttributes.MouseIdentifier =
00709                         BALLPOINT_I8042_HARDWARE;
00710                     break;
00711                 case 0x03:
00712                 case 0x04:
00713                     DeviceExtension->MouseAttributes.MouseIdentifier =
00714                         WHEELMOUSE_I8042_HARDWARE;
00715                     break;
00716                 default:
00717                     DeviceExtension->MouseAttributes.MouseIdentifier =
00718                         MOUSE_I8042_HARDWARE;
00719             }
00720             DeviceExtension->MouseResetState++;
00721             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE8);
00722             return TRUE;
00723         case ExpectingSetResolutionDefaultACK:
00724             DeviceExtension->MouseResetState++;
00725             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x00);
00726             return TRUE;
00727         case ExpectingSetResolutionDefaultValueACK:
00728             DeviceExtension->MouseResetState = ExpectingSetScaling1to1ACK;
00729             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE6);
00730             return TRUE;
00731         case ExpectingSetScaling1to1ACK:
00732         case ExpectingSetScaling1to1ACK2:
00733             DeviceExtension->MouseResetState++;
00734             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE6);
00735             return TRUE;
00736         case ExpectingSetScaling1to1ACK3:
00737             DeviceExtension->MouseResetState++;
00738             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE9);
00739             return TRUE;
00740         case ExpectingReadMouseStatusACK:
00741             DeviceExtension->MouseResetState++;
00742             return TRUE;
00743         case ExpectingReadMouseStatusByte1:
00744             DeviceExtension->MouseLogiBuffer[0] = Value;
00745             DeviceExtension->MouseResetState++;
00746             return TRUE;
00747         case ExpectingReadMouseStatusByte2:
00748             DeviceExtension->MouseLogiBuffer[1] = Value;
00749             DeviceExtension->MouseResetState++;
00750             return TRUE;
00751         case ExpectingReadMouseStatusByte3:
00752             DeviceExtension->MouseLogiBuffer[2] = Value;
00753             /* Now MouseLogiBuffer is a set of info. If the second
00754              * byte is 0, the mouse didn't understand the magic
00755              * code. Otherwise, it it a Logitech and the second byte
00756              * is the number of buttons, bit 7 of the first byte tells
00757              * if it understands special E7 commands, the rest is an ID.
00758              */
00759             if (DeviceExtension->MouseLogiBuffer[1])
00760             {
00761                 DeviceExtension->MouseAttributes.NumberOfButtons =
00762                     DeviceExtension->MouseLogiBuffer[1];
00763                 DeviceExtension->MouseType = Ps2pp;
00764                 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
00765                 DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
00766                 /* TODO: Go through EnableWheel and Enable5Buttons */
00767                 return TRUE;
00768             }
00769             DeviceExtension->MouseResetState = EnableWheel;
00770             i8042MouResetIsr(DeviceExtension, Status, Value);
00771             return TRUE;
00772         case EnableWheel:
00773             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
00774             DeviceExtension->MouseResetState = 1001;
00775             return TRUE;
00776         case 1001:
00777             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xC8);
00778             DeviceExtension->MouseResetState++;
00779             return TRUE;
00780         case 1002:
00781         case 1004:
00782             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
00783             DeviceExtension->MouseResetState++;
00784             return TRUE;
00785         case 1003:
00786             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x64);
00787             DeviceExtension->MouseResetState++;
00788             return TRUE;
00789         case 1005:
00790             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x50);
00791             DeviceExtension->MouseResetState++;
00792             return TRUE;
00793         case 1006:
00794             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2);
00795             DeviceExtension->MouseResetState++;
00796             return TRUE;
00797         case 1007:
00798             /* Ignore ACK */
00799             DeviceExtension->MouseResetState++;
00800             return TRUE;
00801         case 1008:
00802             if (0x03 == Value) {
00803                 /* It's either an Intellimouse or Intellimouse Explorer. */
00804                 DeviceExtension->MouseAttributes.NumberOfButtons = 3;
00805                 DeviceExtension->MouseAttributes.MouseIdentifier =
00806                     WHEELMOUSE_I8042_HARDWARE;
00807                 DeviceExtension->MouseType = Intellimouse;
00808                 DeviceExtension->MouseResetState = Enable5Buttons;
00809                 i8042MouResetIsr(DeviceExtension, Status, Value);
00810             }
00811             else
00812             {
00813                 /* Just set the default settings and be done */
00814                 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
00815                 DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
00816             }
00817             return TRUE;
00818         case Enable5Buttons:
00819             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
00820             DeviceExtension->MouseResetState = 1021;
00821             return TRUE;
00822         case 1022:
00823         case 1024:
00824             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
00825             DeviceExtension->MouseResetState++;
00826             return TRUE;
00827         case 1021:
00828         case 1023:
00829             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xC8);
00830             DeviceExtension->MouseResetState++;
00831             return TRUE;
00832         case 1025:
00833             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x50);
00834             DeviceExtension->MouseResetState++;
00835             return TRUE;
00836         case 1026:
00837             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF2);
00838             DeviceExtension->MouseResetState++;
00839             return TRUE;
00840         case 1027:
00841             if (0x04 == Value)
00842             {
00843                 DeviceExtension->MouseAttributes.NumberOfButtons = 5;
00844                 DeviceExtension->MouseAttributes.MouseIdentifier =
00845                     WHEELMOUSE_I8042_HARDWARE;
00846                 DeviceExtension->MouseType = IntellimouseExplorer;
00847             }
00848             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF3);
00849             DeviceExtension->MouseResetState = ExpectingSetSamplingRateACK;
00850             return TRUE;
00851         case ExpectingSetSamplingRateACK:
00852             DeviceExtension->MouseHook.IsrWritePort(
00853                 DeviceExtension->MouseHook.CallContext,
00854                 (UCHAR)DeviceExtension->MouseAttributes.SampleRate);
00855             DeviceExtension->MouseResetState++;
00856             return TRUE;
00857         case ExpectingSetSamplingRateValueACK:
00858             if (MOUSE_NACK == Value)
00859             {
00860                 DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0x3C);
00861                 DeviceExtension->MouseAttributes.SampleRate = (USHORT)PortDeviceExtension->Settings.SampleRate;
00862                 DeviceExtension->MouseResetState = 1040;
00863                 return TRUE;
00864             }
00865         case 1040:  /* Fallthrough */
00866             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xE8);
00867             DeviceExtension->MouseResetState = ExpectingFinalResolutionACK;
00868             return TRUE;
00869         case ExpectingFinalResolutionACK:
00870             DeviceExtension->MouseHook.IsrWritePort(
00871                 DeviceExtension->MouseHook.CallContext,
00872                 (UCHAR)(PortDeviceExtension->Settings.MouseResolution & 0xff));
00873             INFO_(I8042PRT, "Mouse resolution %lu\n",
00874                 PortDeviceExtension->Settings.MouseResolution);
00875             DeviceExtension->MouseResetState = ExpectingFinalResolutionValueACK;
00876             return TRUE;
00877         case ExpectingFinalResolutionValueACK:
00878             DeviceExtension->MouseHook.IsrWritePort(DeviceExtension->MouseHook.CallContext, 0xF4);
00879             DeviceExtension->MouseResetState = ExpectingEnableACK;
00880             return TRUE;
00881         case ExpectingEnableACK:
00882             PortDeviceExtension->Flags |= MOUSE_PRESENT;
00883             DeviceExtension->MouseState = MouseIdle;
00884             DeviceExtension->MouseTimeoutState = TimeoutCancel;
00885             INFO_(I8042PRT, "Mouse type = %u\n", DeviceExtension->MouseType);
00886             return TRUE;
00887         default:
00888             if (DeviceExtension->MouseResetState < 100 || DeviceExtension->MouseResetState > 999)
00889                 ERR_(I8042PRT, "MouseResetState went out of range: %lu\n", DeviceExtension->MouseResetState);
00890             return FALSE;
00891     }
00892 }
00893 
00894 BOOLEAN NTAPI
00895 i8042MouInterruptService(
00896     IN PKINTERRUPT Interrupt,
00897     PVOID Context)
00898 {
00899     PI8042_MOUSE_EXTENSION DeviceExtension;
00900     PPORT_DEVICE_EXTENSION PortDeviceExtension;
00901     ULONG Counter;
00902     UCHAR Output = 0, PortStatus = 0;
00903     NTSTATUS Status;
00904 
00905     UNREFERENCED_PARAMETER(Interrupt);
00906 
00907     DeviceExtension = (PI8042_MOUSE_EXTENSION)Context;
00908     PortDeviceExtension = DeviceExtension->Common.PortDeviceExtension;
00909     Counter = PortDeviceExtension->Settings.PollStatusIterations;
00910 
00911     while (Counter)
00912     {
00913         Status = i8042ReadStatus(PortDeviceExtension, &PortStatus);
00914         if (!NT_SUCCESS(Status))
00915         {
00916             WARN_(I8042PRT, "i8042ReadStatus() failed with status 0x%08lx\n", Status);
00917             return FALSE;
00918         }
00919         Status = i8042ReadMouseData(PortDeviceExtension, &Output);
00920         if (NT_SUCCESS(Status))
00921             break;
00922         KeStallExecutionProcessor(1);
00923         Counter--;
00924     }
00925     if (Counter == 0)
00926     {
00927         WARN_(I8042PRT, "Spurious i8042 mouse interrupt\n");
00928         return FALSE;
00929     }
00930 
00931     INFO_(I8042PRT, "Got: 0x%02x\n", Output);
00932 
00933     if (i8042PacketIsr(PortDeviceExtension, Output))
00934     {
00935         if (PortDeviceExtension->PacketComplete)
00936         {
00937             TRACE_(I8042PRT, "Packet complete\n");
00938             KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
00939         }
00940         TRACE_(I8042PRT, "Irq eaten by packet\n");
00941         return TRUE;
00942     }
00943 
00944     TRACE_(I8042PRT, "Irq is mouse input\n");
00945 
00946     i8042MouInputTestTimeout(DeviceExtension);
00947 
00948     if (i8042MouResetIsr(DeviceExtension, PortStatus, Output))
00949     {
00950         TRACE_(I8042PRT, "Handled by ResetIsr or hooked Isr\n");
00951         if (NoChange != DeviceExtension->MouseTimeoutState) {
00952             KeInsertQueueDpc(&DeviceExtension->DpcMouse, NULL, NULL);
00953         }
00954         return TRUE;
00955     }
00956 
00957     if (DeviceExtension->MouseType == Ps2pp)
00958         i8042MouHandlePs2pp(DeviceExtension, Output);
00959     else
00960         i8042MouHandle(DeviceExtension, Output);
00961 
00962     return TRUE;
00963 }

Generated on Sat May 26 2012 04:16:00 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.