reactos/drivers/hid/kbdhid/kbdhid.c

856 lines
27 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS HID Stack
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/hid/kbdhid/kbdhid.c
* PURPOSE: Keyboard HID Driver
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "kbdhid.h"
VOID
KbdHid_DispatchInputData(
IN PKBDHID_DEVICE_EXTENSION DeviceExtension,
IN PKEYBOARD_INPUT_DATA InputData)
{
KIRQL OldIrql;
ULONG InputDataConsumed;
if (!DeviceExtension->ClassService)
return;
/* sanity check */
ASSERT(DeviceExtension->ClassService);
ASSERT(DeviceExtension->ClassDeviceObject);
/* raise irql */
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
/* dispatch input data */
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed);
/* lower irql to previous level */
KeLowerIrql(OldIrql);
}
BOOLEAN
NTAPI
KbdHid_InsertScanCodes(
IN PVOID Context,
IN PCHAR NewScanCodes,
IN ULONG Length)
{
//KEYBOARD_INPUT_DATA InputData;
ULONG Index;
for(Index = 0; Index < Length; Index++)
{
DPRINT1("[KBDHID] ScanCode Index %lu ScanCode %x\n", Index, NewScanCodes[Index] & 0xFF);
//
// TODO: set up input data
//
//KbdHid_DispatchInputData((PKBDHID_DEVICE_EXTENSION)Context, &InputData);
}
//
// done
//
return TRUE;
}
NTSTATUS
NTAPI
KbdHid_ReadCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
PKBDHID_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
ULONG ButtonLength;
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)Context;
if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD ||
Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED ||
Irp->IoStatus.Status == STATUS_CANCELLED ||
DeviceExtension->StopReadReport)
{
/* failed to read or should be stopped*/
DPRINT1("[KBDHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status);
/* report no longer active */
DeviceExtension->ReadReportActive = FALSE;
/* request stopping of the report cycle */
DeviceExtension->StopReadReport = FALSE;
/* signal completion event */
KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0);
return STATUS_MORE_PROCESSING_REQUIRED;
}
/* get current usages */
ButtonLength = DeviceExtension->UsageListLength;
Status = HidP_GetUsagesEx(HidP_Input, HIDP_LINK_COLLECTION_UNSPECIFIED, DeviceExtension->CurrentUsageList, &ButtonLength, DeviceExtension->PreparsedData, DeviceExtension->Report, DeviceExtension->ReportLength);
ASSERT(Status == HIDP_STATUS_SUCCESS);
/* FIXME check if needs mapping */
/* get usage difference */
Status = HidP_UsageAndPageListDifference(DeviceExtension->PreviousUsageList, DeviceExtension->CurrentUsageList, DeviceExtension->BreakUsageList, DeviceExtension->MakeUsageList, DeviceExtension->UsageListLength);
ASSERT(Status == HIDP_STATUS_SUCCESS);
/* replace previous usage list with current list */
RtlMoveMemory(DeviceExtension->PreviousUsageList, DeviceExtension->CurrentUsageList, sizeof(USAGE_AND_PAGE) * DeviceExtension->UsageListLength);
/* translate break usage list */
HidP_TranslateUsageAndPagesToI8042ScanCodes(DeviceExtension->BreakUsageList, DeviceExtension->UsageListLength, HidP_Keyboard_Break, &DeviceExtension->ModifierState, KbdHid_InsertScanCodes, DeviceExtension);
ASSERT(Status == HIDP_STATUS_SUCCESS);
/* translate new usage list */
HidP_TranslateUsageAndPagesToI8042ScanCodes(DeviceExtension->MakeUsageList, DeviceExtension->UsageListLength, HidP_Keyboard_Make, &DeviceExtension->ModifierState, KbdHid_InsertScanCodes, DeviceExtension);
ASSERT(Status == HIDP_STATUS_SUCCESS);
/* re-init read */
KbdHid_InitiateRead(DeviceExtension);
/* stop completion */
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
KbdHid_InitiateRead(
IN PKBDHID_DEVICE_EXTENSION DeviceExtension)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
/* re-use irp */
IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS);
/* init irp */
DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL;
/* get next stack location */
IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp);
/* init stack location */
IoStack->Parameters.Read.Length = DeviceExtension->ReportLength;
IoStack->Parameters.Read.Key = 0;
IoStack->Parameters.Read.ByteOffset.QuadPart = 0LL;
IoStack->MajorFunction = IRP_MJ_READ;
IoStack->FileObject = DeviceExtension->FileObject;
/* set completion routine */
IoSetCompletionRoutine(DeviceExtension->Irp, KbdHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE);
/* read is active */
DeviceExtension->ReadReportActive = TRUE;
/* start the read */
Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp);
/* done */
return Status;
}
NTSTATUS
NTAPI
KbdHid_CreateCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
KeSetEvent((PKEVENT)Context, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
NTAPI
KbdHid_Create(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
KEVENT Event;
PKBDHID_DEVICE_EXTENSION DeviceExtension;
DPRINT1("[KBDHID]: IRP_MJ_CREATE\n");
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* get stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
/* copy stack location to next */
IoCopyCurrentIrpStackLocationToNext(Irp);
/* init event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* prepare irp */
IoSetCompletionRoutine(Irp, KbdHid_CreateCompletion, &Event, TRUE, TRUE, TRUE);
/* call lower driver */
Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* request pending */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
}
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed */
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
/* is the driver already in use */
if (DeviceExtension->FileObject == NULL)
{
/* did the caller specify correct attributes */
ASSERT(IoStack->Parameters.Create.SecurityContext);
if (IoStack->Parameters.Create.SecurityContext->DesiredAccess)
{
/* store file object */
DeviceExtension->FileObject = IoStack->FileObject;
/* reset event */
KeResetEvent(&DeviceExtension->ReadCompletionEvent);
/* initiating read */
Status = KbdHid_InitiateRead(DeviceExtension);
DPRINT1("[KBDHID] KbdHid_InitiateRead: status %x\n", Status);
if (Status == STATUS_PENDING)
{
/* report irp is pending */
Status = STATUS_SUCCESS;
}
}
}
/* complete request */
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
KbdHid_Close(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PKBDHID_DEVICE_EXTENSION DeviceExtension;
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
if (DeviceExtension->ReadReportActive)
{
/* request stopping of the report cycle */
DeviceExtension->StopReadReport = TRUE;
/* wait until the reports have been read */
KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
/* cancel irp */
IoCancelIrp(DeviceExtension->Irp);
}
DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
/* remove file object */
DeviceExtension->FileObject = NULL;
/* skip location */
IoSkipCurrentIrpStackLocation(Irp);
/* pass irp to down the stack */
return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
}
NTSTATUS
NTAPI
KbdHid_InternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PKBDHID_DEVICE_EXTENSION DeviceExtension;
PCONNECT_DATA Data;
PKEYBOARD_ATTRIBUTES Attributes;
/* get current stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
DPRINT1("[KBDHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_ATTRIBUTES)
{
/* verify output buffer length */
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
{
/* invalid request */
DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n");
Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_BUFFER_TOO_SMALL;
}
/* get output buffer */
Attributes = (PKEYBOARD_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer;
/* copy attributes */
RtlCopyMemory(Attributes, &DeviceExtension->Attributes, sizeof(KEYBOARD_ATTRIBUTES));
/* complete request */
Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_CONNECT)
{
/* verify input buffer length */
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
{
/* invalid request */
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_PARAMETER;
}
/* is it already connected */
if (DeviceExtension->ClassService)
{
/* already connected */
Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SHARING_VIOLATION;
}
/* get connect data */
Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
/* store connect details */
DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject;
DeviceExtension->ClassService = Data->ClassService;
/* completed successfully */
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_DISCONNECT)
{
/* not implemented */
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_ENABLE)
{
/* not supported */
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_SUPPORTED;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_KEYBOARD_DISABLE)
{
/* not supported */
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_SUPPORTED;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_INDICATORS)
{
/* not implemented */
DPRINT1("IOCTL_KEYBOARD_QUERY_INDICATORS not implemented\n");
ASSERT(FALSE);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_TYPEMATIC)
{
/* not implemented */
DPRINT1("IOCTL_KEYBOARD_QUERY_TYPEMATIC not implemented\n");
ASSERT(FALSE);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_SET_INDICATORS)
{
/* not implemented */
DPRINT1("IOCTL_KEYBOARD_SET_INDICATORS not implemented\n");
ASSERT(FALSE);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_SET_TYPEMATIC)
{
/* not implemented */
DPRINT1("IOCTL_KEYBOARD_SET_TYPEMATIC not implemented\n");
ASSERT(FALSE);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION)
{
/* not implemented */
DPRINT1("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION not implemented\n");
ASSERT(FALSE);
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
/* unknown control code */
DPRINT1("[KBDHID] Unknown DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
/* unknown request not supported */
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_SUPPORTED;
}
NTSTATUS
NTAPI
KbdHid_DeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PKBDHID_DEVICE_EXTENSION DeviceExtension;
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* skip stack location */
IoSkipCurrentIrpStackLocation(Irp);
/* pass and forget */
return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
}
NTSTATUS
NTAPI
KbdHid_Power(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
KbdHid_SubmitRequest(
PDEVICE_OBJECT DeviceObject,
ULONG IoControlCode,
ULONG InputBufferSize,
PVOID InputBuffer,
ULONG OutputBufferSize,
PVOID OutputBuffer)
{
KEVENT Event;
PKBDHID_DEVICE_EXTENSION DeviceExtension;
PIRP Irp;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* init event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* build request */
Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus);
if (!Irp)
{
/* no memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* send request */
Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
/* wait for request to complete */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
/* done */
return Status;
}
NTSTATUS
NTAPI
KbdHid_StartDevice(
IN PDEVICE_OBJECT DeviceObject)
{
NTSTATUS Status;
ULONG Buttons;
HID_COLLECTION_INFORMATION Information;
PHIDP_PREPARSED_DATA PreparsedData;
HIDP_CAPS Capabilities;
PKBDHID_DEVICE_EXTENSION DeviceExtension;
PUSAGE_AND_PAGE Buffer;
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* query collection information */
Status = KbdHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION, 0, NULL, sizeof(HID_COLLECTION_INFORMATION), &Information);
if (!NT_SUCCESS(Status))
{
/* failed to query collection information */
DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status);
return Status;
}
/* lets allocate space for preparsed data */
PreparsedData = (PHIDP_PREPARSED_DATA)ExAllocatePool(NonPagedPool, Information.DescriptorSize);
if (!PreparsedData)
{
/* no memory */
DPRINT1("[KBDHID] no memory size %u\n", Information.DescriptorSize);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* now obtain the preparsed data */
Status = KbdHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, 0, NULL, Information.DescriptorSize, PreparsedData);
if (!NT_SUCCESS(Status))
{
/* failed to get preparsed data */
DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status);
ExFreePool(PreparsedData);
return Status;
}
/* lets get the caps */
Status = HidP_GetCaps(PreparsedData, &Capabilities);
if (Status != HIDP_STATUS_SUCCESS)
{
/* failed to get capabilities */
DPRINT1("[KBDHID] failed to obtain caps with %x\n", Status);
ExFreePool(PreparsedData);
return Status;
}
DPRINT1("[KBDHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength);
/* init input report*/
DeviceExtension->ReportLength = Capabilities.InputReportByteLength;
ASSERT(DeviceExtension->ReportLength);
DeviceExtension->Report = (PCHAR)ExAllocatePool(NonPagedPool, DeviceExtension->ReportLength);
ASSERT(DeviceExtension->Report);
RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength);
/* build mdl */
DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL);
ASSERT(DeviceExtension->ReportMDL);
/* init mdl */
MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL);
/* get max number of buttons */
Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData);
DPRINT1("[KBDHID] Buttons %lu\n", Buttons);
ASSERT(Buttons > 0);
/* now allocate an array for those buttons */
Buffer = (PUSAGE_AND_PAGE)ExAllocatePool(NonPagedPool, sizeof(USAGE_AND_PAGE) * 4 * Buttons);
if (!Buffer)
{
/* no memory */
ExFreePool(PreparsedData);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* init usage lists */
RtlZeroMemory(Buffer, sizeof(USAGE_AND_PAGE) * 4 * Buttons);
DeviceExtension->CurrentUsageList = Buffer;
Buffer += Buttons;
DeviceExtension->PreviousUsageList = Buffer;
Buffer += Buttons;
DeviceExtension->MakeUsageList = Buffer;
Buffer += Buttons;
DeviceExtension->BreakUsageList = Buffer;
//
// FIMXE: implement device hacks
//
// UsageMappings
// KeyboardTypeOverride
// KeyboardSubTypeOverride
// KeyboardNumberTotalKeysOverride
// KeyboardNumberFunctionKeysOverride
// KeyboardNumberIndicatorsOverride
/* store number of buttons */
DeviceExtension->UsageListLength = (USHORT)Buttons;
/* store preparsed data */
DeviceExtension->PreparsedData = PreparsedData;
/* completed successfully */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
KbdHid_StartDeviceCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
KeSetEvent((PKEVENT)Context, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
NTAPI
KbdHid_Flush(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PKBDHID_DEVICE_EXTENSION DeviceExtension;
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* skip current stack location */
IoSkipCurrentIrpStackLocation(Irp);
/* get next stack location */
IoStack = IoGetNextIrpStackLocation(Irp);
/* change request to hid flush queue request */
IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
/* call device */
return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
}
NTSTATUS
NTAPI
KbdHid_Pnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
KEVENT Event;
NTSTATUS Status;
PKBDHID_DEVICE_EXTENSION DeviceExtension;
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* get current irp stack */
IoStack = IoGetCurrentIrpStackLocation(Irp);
DPRINT1("[KBDHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction);
if (IoStack->MinorFunction == IRP_MN_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || IoStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE || IoStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE)
{
/* indicate success */
Irp->IoStatus.Status = STATUS_SUCCESS;
/* skip irp stack location */
IoSkipCurrentIrpStackLocation(Irp);
/* dispatch to lower device */
return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
}
else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
{
/* FIXME synchronization */
/* cancel irp */
IoCancelIrp(DeviceExtension->Irp);
/* indicate success */
Irp->IoStatus.Status = STATUS_SUCCESS;
/* skip irp stack location */
IoSkipCurrentIrpStackLocation(Irp);
/* dispatch to lower device */
Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
IoFreeIrp(DeviceExtension->Irp);
IoDetachDevice(DeviceExtension->NextDeviceObject);
IoDeleteDevice(DeviceObject);
return Status;
}
else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
{
/* init event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* copy stack location */
IoCopyCurrentIrpStackLocationToNext (Irp);
/* set completion routine */
IoSetCompletionRoutine(Irp, KbdHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE);
Irp->IoStatus.Status = 0;
/* pass request */
Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
if (!NT_SUCCESS(Status))
{
/* failed */
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
/* lets start the device */
Status = KbdHid_StartDevice(DeviceObject);
DPRINT1("KbdHid_StartDevice %x\n", Status);
/* complete request */
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
/* done */
return Status;
}
else
{
/* skip irp stack location */
IoSkipCurrentIrpStackLocation(Irp);
/* dispatch to lower device */
return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
}
}
NTSTATUS
NTAPI
KbdHid_AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
NTSTATUS Status;
PDEVICE_OBJECT DeviceObject, NextDeviceObject;
PKBDHID_DEVICE_EXTENSION DeviceExtension;
POWER_STATE State;
/* create device object */
Status = IoCreateDevice(DriverObject, sizeof(KBDHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_KEYBOARD, 0, FALSE, &DeviceObject);
if (!NT_SUCCESS(Status))
{
/* failed to create device object */
return Status;
}
/* now attach it */
NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
if (!NextDeviceObject)
{
/* failed to attach */
IoDeleteDevice(DeviceObject);
return STATUS_DEVICE_NOT_CONNECTED;
}
/* get device extension */
DeviceExtension = (PKBDHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* zero extension */
RtlZeroMemory(DeviceExtension, sizeof(KBDHID_DEVICE_EXTENSION));
/* init device extension */
DeviceExtension->NextDeviceObject = NextDeviceObject;
KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE);
/* init keyboard attributes */
DeviceExtension->Attributes.KeyboardIdentifier.Type = KEYBOARD_TYPE_UNKNOWN;
DeviceExtension->Attributes.KeyboardIdentifier.Subtype = MICROSOFT_KBD_101_TYPE;
DeviceExtension->Attributes.NumberOfFunctionKeys = MICROSOFT_KBD_FUNC;
DeviceExtension->Attributes.NumberOfIndicators = 3; // caps, num lock, scroll lock
DeviceExtension->Attributes.NumberOfKeysTotal = 101;
DeviceExtension->Attributes.InputDataQueueLength = 1;
DeviceExtension->Attributes.KeyRepeatMinimum.Rate = KEYBOARD_TYPEMATIC_RATE_MINIMUM;
DeviceExtension->Attributes.KeyRepeatMinimum.Delay = KEYBOARD_TYPEMATIC_DELAY_MINIMUM;
DeviceExtension->Attributes.KeyRepeatMaximum.Rate = KEYBOARD_TYPEMATIC_RATE_DEFAULT;
DeviceExtension->Attributes.KeyRepeatMaximum.Delay = KEYBOARD_TYPEMATIC_DELAY_MAXIMUM;
/* allocate irp */
DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE);
/* FIXME handle allocation error */
ASSERT(DeviceExtension->Irp);
/* set power state to D0 */
State.DeviceState = PowerDeviceD0;
PoSetPowerState(DeviceObject, DevicePowerState, State);
/* init device object */
DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
/* completed successfully */
return STATUS_SUCCESS;
}
VOID
NTAPI
KbdHid_Unload(
IN PDRIVER_OBJECT DriverObject)
{
UNIMPLEMENTED
}
NTSTATUS
NTAPI
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegPath)
{
/* initialize driver object */
DriverObject->DriverUnload = KbdHid_Unload;
DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdHid_Create;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdHid_Close;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = KbdHid_Flush;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdHid_DeviceControl;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = KbdHid_InternalDeviceControl;
DriverObject->MajorFunction[IRP_MJ_POWER] = KbdHid_Power;
DriverObject->MajorFunction[IRP_MJ_PNP] = KbdHid_Pnp;
DriverObject->DriverUnload = KbdHid_Unload;
DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice;
/* done */
return STATUS_SUCCESS;
}