[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