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

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

Generated on Sun May 27 2012 04:17:51 for ReactOS by doxygen 1.7.6.1

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