From: Aric Stewart Subject: [8/13](resend)hidclass.sys: Add a processing thread for HID devices Message-Id: <55E6E54A.4040905@codeweavers.com> Date: Wed, 2 Sep 2015 07:02:18 -0500 --- dlls/hidclass.sys/buffer.c | 21 ++++++ dlls/hidclass.sys/device.c | 175 +++++++++++++++++++++++++++++++++++++++++++++ dlls/hidclass.sys/hid.h | 2 + dlls/hidclass.sys/pnp.c | 2 + 4 files changed, 200 insertions(+) diff --git a/dlls/hidclass.sys/buffer.c b/dlls/hidclass.sys/buffer.c index 6f09393..94e3372 100644 --- a/dlls/hidclass.sys/buffer.c +++ b/dlls/hidclass.sys/buffer.c @@ -140,3 +140,24 @@ void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index) ring->pointers[index] = 0xffffffff; LeaveCriticalSection(&ring->lock); } + +void RingBuffer_Write(struct ReportRingBuffer *ring, void *data) +{ + UINT i; + + EnterCriticalSection(&ring->lock); + memcpy(&ring->buffer[ring->end * ring->buffer_size], data, ring->buffer_size); + ring->end++; + if (ring->end == ring->size) + ring->end = 0; + if (ring->start == ring->end) + { + ring->start++; + if (ring->start == ring->size) + ring->start = 0; + } + for (i = 0; i < ring->pointer_alloc; i++) + if (ring->pointers[i] == ring->end) + ring->pointers[i] = ring->start; + LeaveCriticalSection(&ring->lock); +} diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 326c994..e09a96c 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -198,6 +198,181 @@ void HID_DeleteDevice(HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT *device IoDeleteDevice(device); } +static void HID_Device_processQueue(DEVICE_OBJECT *device) +{ + LIST_ENTRY *entry; + IRP *irp; + BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + UINT buffer_size = RingBuffer_GetBufferSize(ext->ring_buffer); + HID_XFER_PACKET *packet; + + packet = HeapAlloc(GetProcessHeap(), 0, buffer_size); + + entry = RemoveHeadList(&ext->irp_queue); + while(entry != &ext->irp_queue) + { + int ptr; + irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry); + ptr = (int)irp->Tail.Overlay.OriginalFileObject->FsContext; + + buffer_size = RingBuffer_GetBufferSize(ext->ring_buffer); + RingBuffer_Read(ext->ring_buffer, ptr, packet, &buffer_size); + if (buffer_size) + { + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); + TRACE_(hid_report)("Processing Request (%i)\n",ptr); + if (irpsp->Parameters.Read.Length >= packet->reportBufferLen) + { + memcpy(irp->AssociatedIrp.SystemBuffer, packet->reportBuffer, packet->reportBufferLen); + irp->IoStatus.Information = packet->reportBufferLen; + irp->IoStatus.u.Status = STATUS_SUCCESS; + } + else + { + irp->IoStatus.Information = 0; + irp->IoStatus.u.Status = STATUS_BUFFER_OVERFLOW; + } + } + else + { + irp->IoStatus.Information = 0; + irp->IoStatus.u.Status = STATUS_UNSUCCESSFUL; + } + IoCompleteRequest( irp, IO_NO_INCREMENT ); + entry = RemoveHeadList(&ext->irp_queue); + } + HeapFree(GetProcessHeap(), 0, packet); +} + +static NTSTATUS WINAPI read_Completion(DEVICE_OBJECT *deviceObject, IRP *irp, void *context ) +{ + SetEvent(irp->UserEvent); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +static DWORD CALLBACK hid_device_thread(void *args) +{ + DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; + + IRP *irp; + IO_STATUS_BLOCK irp_status; + IO_STACK_LOCATION *irpsp; + DWORD rc; + HANDLE events[2]; + NTSTATUS ntrc; + + BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + events[0] = CreateEventA(NULL, FALSE, FALSE, NULL); + events[1] = ext->halt_event; + + if (ext->information.Polled) + { + while(1) + { + HID_XFER_PACKET *packet; + ResetEvent(events[0]); + + packet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*packet) + ext->preparseData->caps.InputReportByteLength); + packet->reportBufferLen = ext->preparseData->caps.InputReportByteLength; + packet->reportBuffer = ((BYTE*)packet) + sizeof(*packet); + packet->reportId = 0; + + irp = IoBuildDeviceIoControlRequest(IOCTL_HID_GET_INPUT_REPORT, + device, NULL, 0, packet, sizeof(packet), TRUE, events[0], + &irp_status); + + irpsp = IoGetNextIrpStackLocation(irp); + irpsp->CompletionRoutine = read_Completion; + irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR; + + ntrc = IoCallDriver(device, irp); + + if (ntrc == STATUS_PENDING) + rc = WaitForMultipleObjects(2, events, FALSE, INFINITE); + + if (irp->IoStatus.u.Status == STATUS_SUCCESS) + { + RingBuffer_Write(ext->ring_buffer, packet); + HID_Device_processQueue(device); + } + + IoCompleteRequest(irp, IO_NO_INCREMENT ); + + rc = WaitForSingleObject(ext->halt_event, ext->poll_interval); + + if (rc == WAIT_OBJECT_0) + break; + else if (rc != WAIT_TIMEOUT) + ERR("Wait returned unexpected value %x\n",rc); + } + } + else + { + INT exit_now = FALSE; + + HID_XFER_PACKET *packet; + packet = HeapAlloc(GetProcessHeap(), 0, sizeof(*packet) + ext->preparseData->caps.InputReportByteLength); + packet->reportBufferLen = ext->preparseData->caps.InputReportByteLength; + packet->reportBuffer = ((BYTE*)packet) + sizeof(*packet); + packet->reportId = 0; + + while(1) + { + BYTE *buffer; + + buffer = HeapAlloc(GetProcessHeap(), 0, ext->preparseData->caps.InputReportByteLength); + + ResetEvent(events[0]); + + irp = IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT, + device, NULL, 0, buffer, + ext->preparseData->caps.InputReportByteLength, TRUE, events[0], + &irp_status); + + irpsp = IoGetNextIrpStackLocation(irp); + irpsp->CompletionRoutine = read_Completion; + irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR; + + ntrc = IoCallDriver(device, irp); + + if (ntrc == STATUS_PENDING) + { + rc = WaitForMultipleObjects(2, events, FALSE, INFINITE); + + if (rc == WAIT_OBJECT_0 + 1) + exit_now = TRUE; + } + + if (!exit_now && irp->IoStatus.u.Status == STATUS_SUCCESS) + { + packet->reportId = buffer[0]; + memcpy(packet->reportBuffer, buffer, ext->preparseData->caps.InputReportByteLength); + RingBuffer_Write(ext->ring_buffer, packet); + HID_Device_processQueue(device); + } + + IoCompleteRequest(irp, IO_NO_INCREMENT ); + + if (exit_now) + break; + } + + HeapFree(GetProcessHeap(), 0, packet); + } + + CloseHandle(events[0]); + + TRACE("Device thread exiting\n"); + return 1; +} + +void HID_StartDeviceThread(DEVICE_OBJECT *device) +{ + BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + ext->halt_event = CreateEventA(NULL, FALSE, FALSE, NULL); + ext->thread = CreateThread(NULL, 0, hid_device_thread, device, 0, NULL); +} + static NTSTATUS handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP *irp, BASE_DEVICE_EXTENSION *base) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 34ec241..da5064b 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -56,6 +56,7 @@ typedef struct _BASE_DEVICE_EXTENSTION { /* Minidriver Specific stuff will end up here */ } BASE_DEVICE_EXTENSION; +void RingBuffer_Write(struct ReportRingBuffer *buffer, void *data) DECLSPEC_HIDDEN; UINT RingBuffer_AddPointer(struct ReportRingBuffer *buffer) DECLSPEC_HIDDEN; void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index) DECLSPEC_HIDDEN; void RingBuffer_Read(struct ReportRingBuffer *buffer, UINT index, void *output, UINT *size) DECLSPEC_HIDDEN; @@ -81,6 +82,7 @@ minidriver* find_minidriver(DRIVER_OBJECT* driver) DECLSPEC_HIDDEN; NTSTATUS HID_CreateDevice(void *native_device, HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT **device) DECLSPEC_HIDDEN; NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device, LPCWSTR serial, LPCWSTR index) DECLSPEC_HIDDEN; void HID_DeleteDevice(HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT *device) DECLSPEC_HIDDEN; +void HID_StartDeviceThread(DEVICE_OBJECT *device) DECLSPEC_HIDDEN; NTSTATUS WINAPI HID_Device_ioctl(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI HID_Device_read(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 5694b8a..00aca4a 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -164,6 +164,8 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, void *native) ext->ring_buffer = RingBuffer_Create(sizeof(HID_XFER_PACKET) + ext->preparseData->caps.InputReportByteLength); + HID_StartDeviceThread(device); + return STATUS_SUCCESS; }