/* * 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; }