[8/13](resend)hidclass.sys: Add a processing thread for HID devices
Andrew Eikum
aeikum at codeweavers.com
Wed Sep 2 15:43:16 CDT 2015
On Wed, Sep 02, 2015 at 07:02:18AM -0500, Aric Stewart wrote:
> ---
> 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);
I'm not opposed to what you have here, but a get-buffer/commit-buffer
model would avoid an allocation and a memcpy. Although this would
complicate simultaneous writes, if that's a concern.
More information about the wine-devel
mailing list