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

i8042prt.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/i8042prt.c
00005  * PURPOSE:     Driver entry function
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 #define INITGUID
00015 #include "i8042prt.h"
00016 
00017 /* FUNCTIONS *****************************************************************/
00018 
00019 static DRIVER_STARTIO i8042StartIo;
00020 static DRIVER_DISPATCH IrpStub;
00021 static DRIVER_DISPATCH i8042DeviceControl;
00022 static DRIVER_DISPATCH i8042InternalDeviceControl;
00023 DRIVER_INITIALIZE DriverEntry;
00024 
00025 NTSTATUS NTAPI
00026 i8042AddDevice(
00027     IN PDRIVER_OBJECT DriverObject,
00028     IN PDEVICE_OBJECT Pdo)
00029 {
00030     PI8042_DRIVER_EXTENSION DriverExtension;
00031     PFDO_DEVICE_EXTENSION DeviceExtension = NULL;
00032     PDEVICE_OBJECT Fdo = NULL;
00033     ULONG DeviceExtensionSize;
00034     NTSTATUS Status;
00035 
00036     TRACE_(I8042PRT, "i8042AddDevice(%p %p)\n", DriverObject, Pdo);
00037 
00038     DriverExtension = (PI8042_DRIVER_EXTENSION)IoGetDriverObjectExtension(DriverObject, DriverObject);
00039 
00040     if (Pdo == NULL)
00041     {
00042         /* We're getting a NULL Pdo at the first call as
00043          * we are a legacy driver. Ignore it */
00044         return STATUS_SUCCESS;
00045     }
00046 
00047     /* Create new device object. As we don't know if the device would be a keyboard
00048      * or a mouse, we have to allocate the biggest device extension. */
00049     DeviceExtensionSize = MAX(sizeof(I8042_KEYBOARD_EXTENSION), sizeof(I8042_MOUSE_EXTENSION));
00050     Status = IoCreateDevice(
00051         DriverObject,
00052         DeviceExtensionSize,
00053         NULL,
00054         Pdo->DeviceType,
00055         FILE_DEVICE_SECURE_OPEN,
00056         TRUE,
00057         &Fdo);
00058     if (!NT_SUCCESS(Status))
00059     {
00060         WARN_(I8042PRT, "IoCreateDevice() failed with status 0x%08lx\n", Status);
00061         goto cleanup;
00062     }
00063 
00064     DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
00065     RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
00066     DeviceExtension->Type = Unknown;
00067     DeviceExtension->Fdo = Fdo;
00068     DeviceExtension->Pdo = Pdo;
00069     DeviceExtension->PortDeviceExtension = &DriverExtension->Port;
00070     Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
00071     if (!NT_SUCCESS(Status))
00072     {
00073         WARN_(I8042PRT, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
00074         goto cleanup;
00075     }
00076 
00077     ExInterlockedInsertTailList(
00078         &DriverExtension->DeviceListHead,
00079         &DeviceExtension->ListEntry,
00080         &DriverExtension->DeviceListLock);
00081 
00082     Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
00083     return STATUS_SUCCESS;
00084 
00085 cleanup:
00086     if (DeviceExtension && DeviceExtension->LowerDevice)
00087         IoDetachDevice(DeviceExtension->LowerDevice);
00088     if (Fdo)
00089         IoDeleteDevice(Fdo);
00090     return Status;
00091 }
00092 
00093 VOID NTAPI
00094 i8042SendHookWorkItem(
00095     IN PDEVICE_OBJECT DeviceObject,
00096     IN PVOID Context)
00097 {
00098     PI8042_HOOK_WORKITEM WorkItemData;
00099     PFDO_DEVICE_EXTENSION FdoDeviceExtension;
00100     PPORT_DEVICE_EXTENSION PortDeviceExtension;
00101     PDEVICE_OBJECT TopOfStack = NULL;
00102     ULONG IoControlCode;
00103     PVOID InputBuffer;
00104     ULONG InputBufferLength;
00105     IO_STATUS_BLOCK IoStatus;
00106     KEVENT Event;
00107     PIRP NewIrp;
00108     NTSTATUS Status;
00109 
00110     TRACE_(I8042PRT, "i8042SendHookWorkItem(%p %p)\n", DeviceObject, Context);
00111 
00112     WorkItemData = (PI8042_HOOK_WORKITEM)Context;
00113     FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
00114     PortDeviceExtension = FdoDeviceExtension->PortDeviceExtension;
00115 
00116     switch (FdoDeviceExtension->Type)
00117     {
00118         case Keyboard:
00119         {
00120             PI8042_KEYBOARD_EXTENSION DeviceExtension;
00121             DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
00122             IoControlCode = IOCTL_INTERNAL_I8042_HOOK_KEYBOARD;
00123             InputBuffer = &DeviceExtension->KeyboardHook;
00124             InputBufferLength = sizeof(INTERNAL_I8042_HOOK_KEYBOARD);
00125             break;
00126         }
00127         case Mouse:
00128         {
00129             PI8042_MOUSE_EXTENSION DeviceExtension;
00130             DeviceExtension = (PI8042_MOUSE_EXTENSION)FdoDeviceExtension;
00131             IoControlCode = IOCTL_INTERNAL_I8042_HOOK_MOUSE;
00132             InputBuffer = &DeviceExtension->MouseHook;
00133             InputBufferLength = sizeof(INTERNAL_I8042_HOOK_MOUSE);
00134             break;
00135         }
00136         default:
00137         {
00138             ERR_(I8042PRT, "Unknown FDO type %u\n", FdoDeviceExtension->Type);
00139             ASSERT(FALSE);
00140             WorkItemData->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
00141             goto cleanup;
00142         }
00143     }
00144 
00145     KeInitializeEvent(&Event, NotificationEvent, FALSE);
00146     TopOfStack = IoGetAttachedDeviceReference(DeviceObject);
00147 
00148     NewIrp = IoBuildDeviceIoControlRequest(
00149         IoControlCode,
00150         TopOfStack,
00151         InputBuffer,
00152         InputBufferLength,
00153         NULL,
00154         0,
00155         TRUE,
00156         &Event,
00157         &IoStatus);
00158 
00159     if (!NewIrp)
00160     {
00161         WARN_(I8042PRT, "IoBuildDeviceIoControlRequest() failed\n");
00162         WorkItemData->Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
00163         goto cleanup;
00164     }
00165 
00166     Status = IoCallDriver(TopOfStack, NewIrp);
00167     if (Status == STATUS_PENDING)
00168     {
00169         KeWaitForSingleObject(
00170             &Event,
00171             Executive,
00172             KernelMode,
00173             FALSE,
00174             NULL);
00175         Status = IoStatus.Status;
00176     }
00177     if (!NT_SUCCESS(Status))
00178     {
00179         WARN_(I8042PRT, "IoCallDriver() failed with status 0x%08lx\n", Status);
00180         goto cleanup;
00181     }
00182 
00183     if (FdoDeviceExtension->Type == Keyboard)
00184     {
00185         PI8042_KEYBOARD_EXTENSION DeviceExtension;
00186 
00187         DeviceExtension = (PI8042_KEYBOARD_EXTENSION)FdoDeviceExtension;
00188         /* Call the hooked initialization if it exists */
00189         if (DeviceExtension->KeyboardHook.InitializationRoutine)
00190         {
00191             Status = DeviceExtension->KeyboardHook.InitializationRoutine(
00192                 DeviceExtension->KeyboardHook.Context,
00193                 PortDeviceExtension,
00194                 i8042SynchReadPort,
00195                 i8042SynchWritePortKbd,
00196                 FALSE);
00197             if (!NT_SUCCESS(Status))
00198             {
00199                 WARN_(I8042PRT, "KeyboardHook.InitializationRoutine() failed with status 0x%08lx\n", Status);
00200                 WorkItemData->Irp->IoStatus.Status = Status;
00201                 goto cleanup;
00202             }
00203         }
00204     }
00205 
00206     WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS;
00207 
00208 cleanup:
00209     if (TopOfStack != NULL)
00210         ObDereferenceObject(TopOfStack);
00211     WorkItemData->Irp->IoStatus.Information = 0;
00212     IoCompleteRequest(WorkItemData->Irp, IO_NO_INCREMENT);
00213 
00214     IoFreeWorkItem(WorkItemData->WorkItem);
00215     ExFreePoolWithTag(WorkItemData, I8042PRT_TAG);
00216 }
00217 
00218 static VOID NTAPI
00219 i8042StartIo(
00220     IN PDEVICE_OBJECT DeviceObject,
00221     IN PIRP Irp)
00222 {
00223     PFDO_DEVICE_EXTENSION DeviceExtension;
00224 
00225     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
00226     switch (DeviceExtension->Type)
00227     {
00228         case Keyboard:
00229             i8042KbdStartIo(DeviceObject, Irp);
00230             break;
00231         default:
00232             ERR_(I8042PRT, "Unknown FDO type %u\n", DeviceExtension->Type);
00233             ASSERT(FALSE);
00234             break;
00235     }
00236 }
00237 
00238 /* Write the current byte of the packet. Returns FALSE in case
00239  * of problems.
00240  */
00241 static BOOLEAN
00242 i8042PacketWrite(
00243     IN PPORT_DEVICE_EXTENSION DeviceExtension)
00244 {
00245     UCHAR Port = DeviceExtension->PacketPort;
00246 
00247     if (Port)
00248     {
00249         if (!i8042Write(DeviceExtension,
00250                         DeviceExtension->ControlPort,
00251                         Port))
00252         {
00253             /* something is really wrong! */
00254             WARN_(I8042PRT, "Failed to send packet byte!\n");
00255             return FALSE;
00256         }
00257     }
00258 
00259     return i8042Write(DeviceExtension,
00260                       DeviceExtension->DataPort,
00261                       DeviceExtension->Packet.Bytes[DeviceExtension->Packet.CurrentByte]);
00262 }
00263 
00264 BOOLEAN
00265 i8042PacketIsr(
00266     IN PPORT_DEVICE_EXTENSION DeviceExtension,
00267     IN UCHAR Output)
00268 {
00269     if (DeviceExtension->Packet.State == Idle)
00270         return FALSE;
00271 
00272     switch (Output)
00273     {
00274         case KBD_RESEND:
00275             DeviceExtension->PacketResends++;
00276             if (DeviceExtension->PacketResends > DeviceExtension->Settings.ResendIterations)
00277             {
00278                 DeviceExtension->Packet.State = Idle;
00279                 DeviceExtension->PacketComplete = TRUE;
00280                 DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
00281                 DeviceExtension->PacketResends = 0;
00282                 return TRUE;
00283             }
00284             DeviceExtension->Packet.CurrentByte--;
00285             break;
00286 
00287         case KBD_NACK:
00288             DeviceExtension->Packet.State = Idle;
00289             DeviceExtension->PacketComplete = TRUE;
00290             DeviceExtension->PacketResult = STATUS_UNEXPECTED_IO_ERROR;
00291             DeviceExtension->PacketResends = 0;
00292             return TRUE;
00293 
00294         default:
00295             DeviceExtension->PacketResends = 0;
00296     }
00297 
00298     if (DeviceExtension->Packet.CurrentByte >= DeviceExtension->Packet.ByteCount)
00299     {
00300         DeviceExtension->Packet.State = Idle;
00301         DeviceExtension->PacketComplete = TRUE;
00302         DeviceExtension->PacketResult = STATUS_SUCCESS;
00303         return TRUE;
00304     }
00305 
00306     if (!i8042PacketWrite(DeviceExtension))
00307     {
00308         DeviceExtension->Packet.State = Idle;
00309         DeviceExtension->PacketComplete = TRUE;
00310         DeviceExtension->PacketResult = STATUS_IO_TIMEOUT;
00311         return TRUE;
00312     }
00313     DeviceExtension->Packet.CurrentByte++;
00314 
00315     return TRUE;
00316 }
00317 
00318 /*
00319  * This function starts a packet. It must be called with the
00320  * correct DIRQL.
00321  */
00322 NTSTATUS
00323 i8042StartPacket(
00324     IN PPORT_DEVICE_EXTENSION DeviceExtension,
00325     IN PFDO_DEVICE_EXTENSION FdoDeviceExtension,
00326     IN PUCHAR Bytes,
00327     IN ULONG ByteCount,
00328     IN PIRP Irp)
00329 {
00330     KIRQL Irql;
00331     NTSTATUS Status;
00332 
00333     Irql = KeAcquireInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt);
00334 
00335     if (DeviceExtension->Packet.State != Idle)
00336     {
00337         Status = STATUS_DEVICE_BUSY;
00338         goto done;
00339     }
00340 
00341     switch (FdoDeviceExtension->Type)
00342     {
00343         case Keyboard: DeviceExtension->PacketPort = 0; break;
00344         case Mouse: DeviceExtension->PacketPort = CTRL_WRITE_MOUSE; break;
00345         default:
00346             ERR_(I8042PRT, "Unknown FDO type %u\n", FdoDeviceExtension->Type);
00347             ASSERT(FALSE);
00348             Status = STATUS_INTERNAL_ERROR;
00349             goto done;
00350     }
00351 
00352     DeviceExtension->Packet.Bytes = Bytes;
00353     DeviceExtension->Packet.CurrentByte = 0;
00354     DeviceExtension->Packet.ByteCount = ByteCount;
00355     DeviceExtension->Packet.State = SendingBytes;
00356     DeviceExtension->PacketResult = Status = STATUS_PENDING;
00357     DeviceExtension->CurrentIrp = Irp;
00358     DeviceExtension->CurrentIrpDevice = FdoDeviceExtension->Fdo;
00359 
00360     if (!i8042PacketWrite(DeviceExtension))
00361     {
00362         Status = STATUS_IO_TIMEOUT;
00363         DeviceExtension->Packet.State = Idle;
00364         DeviceExtension->PacketResult = STATUS_ABANDONED;
00365         goto done;
00366     }
00367 
00368     DeviceExtension->Packet.CurrentByte++;
00369 
00370 done:
00371     KeReleaseInterruptSpinLock(DeviceExtension->HighestDIRQLInterrupt, Irql);
00372 
00373     if (Status != STATUS_PENDING)
00374     {
00375         DeviceExtension->CurrentIrp = NULL;
00376         DeviceExtension->CurrentIrpDevice = NULL;
00377         Irp->IoStatus.Status = Status;
00378         IoCompleteRequest(Irp, IO_NO_INCREMENT);
00379     }
00380     return Status;
00381 }
00382 
00383 static NTSTATUS NTAPI
00384 IrpStub(
00385     IN PDEVICE_OBJECT DeviceObject,
00386     IN PIRP Irp)
00387 {
00388     NTSTATUS Status = Irp->IoStatus.Status;
00389 
00390     UNREFERENCED_PARAMETER(DeviceObject);
00391 
00392     /* Do nothing */
00393     ASSERT(FALSE);
00394     IoCompleteRequest(Irp, IO_NO_INCREMENT);
00395     return Status;
00396 }
00397 
00398 static NTSTATUS NTAPI
00399 i8042DeviceControl(
00400     IN PDEVICE_OBJECT DeviceObject,
00401     IN PIRP Irp)
00402 {
00403     PFDO_DEVICE_EXTENSION DeviceExtension;
00404 
00405     TRACE_(I8042PRT, "i8042DeviceControl(%p %p)\n", DeviceObject, Irp);
00406     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
00407 
00408     switch (DeviceExtension->Type)
00409     {
00410         case Keyboard:
00411             return i8042KbdDeviceControl(DeviceObject, Irp);
00412             break;
00413         default:
00414             return IrpStub(DeviceObject, Irp);
00415     }
00416 }
00417 
00418 static NTSTATUS NTAPI
00419 i8042InternalDeviceControl(
00420     IN PDEVICE_OBJECT DeviceObject,
00421     IN PIRP Irp)
00422 {
00423     PFDO_DEVICE_EXTENSION DeviceExtension;
00424     ULONG ControlCode;
00425     NTSTATUS Status;
00426 
00427     TRACE_(I8042PRT, "i8042InternalDeviceControl(%p %p)\n", DeviceObject, Irp);
00428     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
00429 
00430     switch (DeviceExtension->Type)
00431     {
00432         case Unknown:
00433         {
00434             ControlCode = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode;
00435             switch (ControlCode)
00436             {
00437                 case IOCTL_INTERNAL_KEYBOARD_CONNECT:
00438                     Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
00439                     break;
00440                 case IOCTL_INTERNAL_MOUSE_CONNECT:
00441                     Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
00442                     break;
00443                 default:
00444                     ERR_(I8042PRT, "Unknown IO control code 0x%lx\n", ControlCode);
00445                     ASSERT(FALSE);
00446                     Status = STATUS_INVALID_DEVICE_REQUEST;
00447                     break;
00448             }
00449             break;
00450         }
00451         case Keyboard:
00452             Status = i8042KbdInternalDeviceControl(DeviceObject, Irp);
00453             break;
00454         case Mouse:
00455             Status = i8042MouInternalDeviceControl(DeviceObject, Irp);
00456             break;
00457         default:
00458             ERR_(I8042PRT, "Unknown FDO type %u\n", DeviceExtension->Type);
00459             ASSERT(FALSE);
00460             Status = STATUS_INTERNAL_ERROR;
00461             IoCompleteRequest(Irp, IO_NO_INCREMENT);
00462             break;
00463     }
00464 
00465     return Status;
00466 }
00467 
00468 NTSTATUS NTAPI
00469 DriverEntry(
00470     IN PDRIVER_OBJECT DriverObject,
00471     IN PUNICODE_STRING RegistryPath)
00472 {
00473     PI8042_DRIVER_EXTENSION DriverExtension;
00474     ULONG i;
00475     NTSTATUS Status;
00476 
00477     /* ROS Hack: ideally, we shouldn't have to initialize debug level this way,
00478        but since the only way is to change it via KDBG, it's better to leave
00479        it here too. */
00480 #if 0
00481     DbgSetDebugFilterState(
00482         DPFLTR_I8042PRT_ID,
00483         (1 << DPFLTR_ERROR_LEVEL) | (1 << DPFLTR_WARNING_LEVEL) |
00484         (1 << DPFLTR_TRACE_LEVEL) /*| (1 << DPFLTR_INFO_LEVEL)*/ | DPFLTR_MASK,
00485         TRUE);
00486 #endif
00487 
00488     Status = IoAllocateDriverObjectExtension(
00489         DriverObject,
00490         DriverObject,
00491         sizeof(I8042_DRIVER_EXTENSION),
00492         (PVOID*)&DriverExtension);
00493     if (!NT_SUCCESS(Status))
00494     {
00495         WARN_(I8042PRT, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
00496         return Status;
00497     }
00498     RtlZeroMemory(DriverExtension, sizeof(I8042_DRIVER_EXTENSION));
00499     KeInitializeSpinLock(&DriverExtension->Port.SpinLock);
00500     InitializeListHead(&DriverExtension->DeviceListHead);
00501     KeInitializeSpinLock(&DriverExtension->DeviceListLock);
00502 
00503     Status = DuplicateUnicodeString(
00504         RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
00505         RegistryPath,
00506         &DriverExtension->RegistryPath);
00507     if (!NT_SUCCESS(Status))
00508     {
00509         WARN_(I8042PRT, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
00510         return Status;
00511     }
00512 
00513     Status = ReadRegistryEntries(RegistryPath, &DriverExtension->Port.Settings);
00514     if (!NT_SUCCESS(Status))
00515     {
00516         WARN_(I8042PRT, "ReadRegistryEntries() failed with status 0x%08lx\n", Status);
00517         return Status;
00518     }
00519 
00520     DriverObject->DriverExtension->AddDevice = i8042AddDevice;
00521     DriverObject->DriverStartIo = i8042StartIo;
00522 
00523     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
00524         DriverObject->MajorFunction[i] = IrpStub;
00525 
00526     DriverObject->MajorFunction[IRP_MJ_CREATE]  = i8042Create;
00527     DriverObject->MajorFunction[IRP_MJ_CLEANUP] = i8042Cleanup;
00528     DriverObject->MajorFunction[IRP_MJ_CLOSE]   = i8042Close;
00529     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = i8042DeviceControl;
00530     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = i8042InternalDeviceControl;
00531     DriverObject->MajorFunction[IRP_MJ_PNP]     = i8042Pnp;
00532 
00533     return STATUS_SUCCESS;
00534 }

Generated on Sun May 27 2012 04:27:49 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.