Aric Stewart : hidclass.sys: Add a processing thread for HID devices.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Oct 14 11:12:51 CDT 2015


Module: wine
Branch: master
Commit: 35938ed8be6c7d2ba05c4779cd8c1c64889487d6
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=35938ed8be6c7d2ba05c4779cd8c1c64889487d6

Author: Aric Stewart <aric at codeweavers.com>
Date:   Thu Oct  8 14:34:35 2015 -0500

hidclass.sys: Add a processing thread for HID devices.

Signed-off-by: Aric Stewart <aric at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/hidclass.sys/buffer.c |  21 ++++++
 dlls/hidclass.sys/device.c | 174 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/hidclass.sys/hid.h    |   2 +
 dlls/hidclass.sys/pnp.c    |   2 +
 4 files changed, 199 insertions(+)

diff --git a/dlls/hidclass.sys/buffer.c b/dlls/hidclass.sys/buffer.c
index af59284..d7770f6 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 b0982f0..358e950 100644
--- a/dlls/hidclass.sys/device.c
+++ b/dlls/hidclass.sys/device.c
@@ -198,6 +198,180 @@ 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 = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
+
+        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 41b9937..1c1eaf3 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(DEVICE_OBJECT *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 7f73e05..c3d6f64 100644
--- a/dlls/hidclass.sys/pnp.c
+++ b/dlls/hidclass.sys/pnp.c
@@ -165,6 +165,8 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
 
     ext->ring_buffer = RingBuffer_Create(sizeof(HID_XFER_PACKET) + ext->preparseData->caps.InputReportByteLength);
 
+    HID_StartDeviceThread(device);
+
     return STATUS_SUCCESS;
 }
 




More information about the wine-cvs mailing list