Commit 1f3fdb3c authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

hidclass.sys: Adjust buffer length according to report IDs usage.

parent e8c6f130
...@@ -81,12 +81,10 @@ static void hid_device_send_input(DEVICE_OBJECT *device, HID_XFER_PACKET *packet ...@@ -81,12 +81,10 @@ static void hid_device_send_input(DEVICE_OBJECT *device, HID_XFER_PACKET *packet
{ {
BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
RAWINPUT *rawinput; RAWINPUT *rawinput;
UCHAR *report, id;
ULONG data_size; ULONG data_size;
INPUT input; INPUT input;
data_size = offsetof(RAWINPUT, data.hid.bRawData) + packet->reportBufferLen; data_size = offsetof(RAWINPUT, data.hid.bRawData) + packet->reportBufferLen;
if (!(id = ext->u.pdo.preparsed_data->reports[0].reportID)) data_size += 1;
if (!(rawinput = malloc(data_size))) if (!(rawinput = malloc(data_size)))
{ {
...@@ -100,10 +98,7 @@ static void hid_device_send_input(DEVICE_OBJECT *device, HID_XFER_PACKET *packet ...@@ -100,10 +98,7 @@ static void hid_device_send_input(DEVICE_OBJECT *device, HID_XFER_PACKET *packet
rawinput->header.wParam = RIM_INPUT; rawinput->header.wParam = RIM_INPUT;
rawinput->data.hid.dwCount = 1; rawinput->data.hid.dwCount = 1;
rawinput->data.hid.dwSizeHid = data_size - offsetof(RAWINPUT, data.hid.bRawData); rawinput->data.hid.dwSizeHid = data_size - offsetof(RAWINPUT, data.hid.bRawData);
memcpy( rawinput->data.hid.bRawData, packet->reportBuffer, packet->reportBufferLen );
report = rawinput->data.hid.bRawData;
if (!id) *report++ = 0;
memcpy(report, packet->reportBuffer, packet->reportBufferLen);
input.type = INPUT_HARDWARE; input.type = INPUT_HARDWARE;
input.hi.uMsg = WM_INPUT; input.hi.uMsg = WM_INPUT;
...@@ -126,15 +121,13 @@ static void HID_Device_processQueue(DEVICE_OBJECT *device) ...@@ -126,15 +121,13 @@ static void HID_Device_processQueue(DEVICE_OBJECT *device)
while((irp = pop_irp_from_queue(ext))) while((irp = pop_irp_from_queue(ext)))
{ {
BYTE *buffer = irp->AssociatedIrp.SystemBuffer, *dst = buffer;
int ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext ); int ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
RingBuffer_Read(ext->u.pdo.ring_buffer, ptr, packet, &buffer_size); RingBuffer_Read(ext->u.pdo.ring_buffer, ptr, packet, &buffer_size);
if (buffer_size) if (buffer_size)
{ {
TRACE_(hid_report)("Processing Request (%i)\n",ptr); TRACE_(hid_report)("Processing Request (%i)\n",ptr);
if (!data->reports[0].reportID) *dst++ = 0; memcpy( irp->AssociatedIrp.SystemBuffer, packet + 1, data->caps.InputReportByteLength );
memcpy( dst, packet + 1, data->caps.InputReportByteLength - (dst - buffer) );
irp->IoStatus.Information = packet->reportBufferLen; irp->IoStatus.Information = packet->reportBufferLen;
irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Status = STATUS_SUCCESS;
} }
...@@ -151,28 +144,42 @@ static void HID_Device_processQueue(DEVICE_OBJECT *device) ...@@ -151,28 +144,42 @@ static void HID_Device_processQueue(DEVICE_OBJECT *device)
static DWORD CALLBACK hid_device_thread(void *args) static DWORD CALLBACK hid_device_thread(void *args)
{ {
DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; DEVICE_OBJECT *device = (DEVICE_OBJECT*)args;
HID_XFER_PACKET *packet; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
BYTE report_id = HID_INPUT_VALUE_CAPS( data )->report_id;
ULONG buffer_len = data->caps.InputReportByteLength;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
HID_XFER_PACKET *packet;
BYTE *buffer;
DWORD rc; DWORD rc;
BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; packet = malloc( sizeof(*packet) + buffer_len );
USHORT report_size = ext->u.pdo.preparsed_data->caps.InputReportByteLength; buffer = (BYTE *)(packet + 1);
packet->reportBuffer = buffer;
packet = malloc(sizeof(*packet) + report_size);
packet->reportBuffer = (BYTE *)packet + sizeof(*packet);
if (ext->u.pdo.information.Polled) if (ext->u.pdo.information.Polled)
{ {
while(1) while(1)
{ {
packet->reportBufferLen = report_size; packet->reportId = buffer[0] = report_id;
packet->reportId = 0; packet->reportBufferLen = buffer_len;
if (!report_id)
{
packet->reportBuffer++;
packet->reportBufferLen--;
}
call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, packet, call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, packet,
sizeof(*packet), &io ); sizeof(*packet), &io );
if (io.Status == STATUS_SUCCESS) if (io.Status == STATUS_SUCCESS)
{ {
if (!report_id) io.Information++;
packet->reportId = buffer[0];
packet->reportBuffer = buffer;
packet->reportBufferLen = io.Information;
RingBuffer_Write(ext->u.pdo.ring_buffer, packet); RingBuffer_Write(ext->u.pdo.ring_buffer, packet);
hid_device_send_input(device, packet); hid_device_send_input(device, packet);
HID_Device_processQueue(device); HID_Device_processQueue(device);
...@@ -193,8 +200,17 @@ static DWORD CALLBACK hid_device_thread(void *args) ...@@ -193,8 +200,17 @@ static DWORD CALLBACK hid_device_thread(void *args)
while(1) while(1)
{ {
packet->reportId = buffer[0] = report_id;
packet->reportBufferLen = buffer_len;
if (!report_id)
{
packet->reportBuffer++;
packet->reportBufferLen--;
}
call_minidriver( IOCTL_HID_READ_REPORT, ext->u.pdo.parent_fdo, NULL, 0, call_minidriver( IOCTL_HID_READ_REPORT, ext->u.pdo.parent_fdo, NULL, 0,
packet->reportBuffer, report_size, &io ); packet->reportBuffer, packet->reportBufferLen, &io );
rc = WaitForSingleObject(ext->u.pdo.halt_event, 0); rc = WaitForSingleObject(ext->u.pdo.halt_event, 0);
if (rc == WAIT_OBJECT_0) if (rc == WAIT_OBJECT_0)
...@@ -202,11 +218,11 @@ static DWORD CALLBACK hid_device_thread(void *args) ...@@ -202,11 +218,11 @@ static DWORD CALLBACK hid_device_thread(void *args)
if (!exit_now && io.Status == STATUS_SUCCESS) if (!exit_now && io.Status == STATUS_SUCCESS)
{ {
if (!report_id) io.Information++;
packet->reportId = buffer[0];
packet->reportBuffer = buffer;
packet->reportBufferLen = io.Information; packet->reportBufferLen = io.Information;
if (ext->u.pdo.preparsed_data->reports[0].reportID)
packet->reportId = packet->reportBuffer[0];
else
packet->reportId = 0;
RingBuffer_Write(ext->u.pdo.ring_buffer, packet); RingBuffer_Write(ext->u.pdo.ring_buffer, packet);
hid_device_send_input(device, packet); hid_device_send_input(device, packet);
HID_Device_processQueue(device); HID_Device_processQueue(device);
...@@ -375,6 +391,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) ...@@ -375,6 +391,7 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data; const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
BYTE report_id = HID_INPUT_VALUE_CAPS( data )->report_id;
NTSTATUS status; NTSTATUS status;
BOOL removed; BOOL removed;
KIRQL irql; KIRQL irql;
...@@ -454,10 +471,9 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) ...@@ -454,10 +471,9 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
} }
case IOCTL_HID_GET_INPUT_REPORT: case IOCTL_HID_GET_INPUT_REPORT:
{ {
HID_XFER_PACKET *packet; HID_XFER_PACKET packet;
ULONG buffer_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength; ULONG buffer_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
UINT packet_size = sizeof(*packet) + buffer_len; BYTE *buffer = MmGetSystemAddressForMdlSafe( irp->MdlAddress, NormalPagePriority );
BYTE *buffer = MmGetSystemAddressForMdlSafe( irp->MdlAddress, NormalPagePriority ), *dst = buffer;
if (!buffer) if (!buffer)
{ {
...@@ -470,24 +486,19 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp) ...@@ -470,24 +486,19 @@ NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
break; break;
} }
packet = malloc(packet_size); packet.reportId = buffer[0];
packet.reportBuffer = buffer;
packet.reportBufferLen = buffer_len;
if (ext->u.pdo.preparsed_data->reports[0].reportID) if (!report_id)
packet->reportId = buffer[0];
else
packet->reportId = 0;
packet->reportBuffer = (BYTE *)packet + sizeof(*packet);
packet->reportBufferLen = buffer_len - 1;
call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, packet,
sizeof(*packet), &irp->IoStatus );
if (irp->IoStatus.Status == STATUS_SUCCESS)
{ {
if (!data->reports[0].reportID) *dst++ = 0; packet.reportId = 0;
memcpy( dst, packet + 1, data->caps.InputReportByteLength - (dst - buffer) ); packet.reportBuffer++;
packet.reportBufferLen--;
} }
free(packet);
call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, &packet,
sizeof(packet), &irp->IoStatus );
break; break;
} }
case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS: case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS:
...@@ -544,7 +555,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) ...@@ -544,7 +555,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp)
const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data; const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
UINT buffer_size = RingBuffer_GetBufferSize(ext->u.pdo.ring_buffer); UINT buffer_size = RingBuffer_GetBufferSize(ext->u.pdo.ring_buffer);
IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
BYTE *buffer = irp->AssociatedIrp.SystemBuffer, *dst = buffer; BYTE report_id = HID_INPUT_VALUE_CAPS( data )->report_id;
NTSTATUS status; NTSTATUS status;
int ptr = -1; int ptr = -1;
BOOL removed; BOOL removed;
...@@ -576,8 +587,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) ...@@ -576,8 +587,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp)
if (buffer_size) if (buffer_size)
{ {
if (!data->reports[0].reportID) *dst++ = 0; memcpy( irp->AssociatedIrp.SystemBuffer, packet + 1, data->caps.InputReportByteLength );
memcpy( dst, packet + 1, data->caps.InputReportByteLength - (dst - buffer) );
irp->IoStatus.Information = packet->reportBufferLen; irp->IoStatus.Information = packet->reportBufferLen;
irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Status = STATUS_SUCCESS;
} }
...@@ -608,19 +618,24 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) ...@@ -608,19 +618,24 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp)
else else
{ {
HID_XFER_PACKET packet; HID_XFER_PACKET packet;
BYTE *buffer = irp->AssociatedIrp.SystemBuffer;
ULONG buffer_len = irpsp->Parameters.Read.Length;
TRACE("No packet, but opportunistic reads enabled\n"); TRACE("No packet, but opportunistic reads enabled\n");
packet.reportId = ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0];
packet.reportBuffer = &((BYTE*)irp->AssociatedIrp.SystemBuffer)[1];
packet.reportBufferLen = irpsp->Parameters.Read.Length - 1;
call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, &packet, packet.reportId = buffer[0];
sizeof(packet), &irp->IoStatus ); packet.reportBuffer = buffer;
packet.reportBufferLen = buffer_len;
if (irp->IoStatus.Status == STATUS_SUCCESS) if (!report_id)
{ {
((BYTE*)irp->AssociatedIrp.SystemBuffer)[0] = packet.reportId; packet.reportId = 0;
irp->IoStatus.Information = packet.reportBufferLen + 1; packet.reportBuffer++;
packet.reportBufferLen--;
} }
call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, &packet,
sizeof(packet), &irp->IoStatus );
} }
} }
free(packet); free(packet);
......
...@@ -479,7 +479,6 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp) ...@@ -479,7 +479,6 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
{ {
ULONG expected_size = 23; ULONG expected_size = 23;
ok(!in_size, "got input size %u\n", in_size); ok(!in_size, "got input size %u\n", in_size);
todo_wine_if(!report_id)
ok(out_size == expected_size, "got output size %u\n", out_size); ok(out_size == expected_size, "got output size %u\n", out_size);
if (polled) if (polled)
...@@ -533,9 +532,8 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp) ...@@ -533,9 +532,8 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
ok(!in_size, "got input size %u\n", in_size); ok(!in_size, "got input size %u\n", in_size);
ok(out_size == sizeof(*packet), "got output size %u\n", out_size); ok(out_size == sizeof(*packet), "got output size %u\n", out_size);
todo_wine_if(packet->reportId == 0x5a || (polled && report_id && packet->reportId == 0)) todo_wine_if(packet->reportId == 0x5a)
ok(packet->reportId == report_id, "got id %u\n", packet->reportId); ok(packet->reportId == report_id, "got id %u\n", packet->reportId);
todo_wine_if(packet->reportBufferLen == 22)
ok(packet->reportBufferLen >= expected_size, "got len %u\n", packet->reportBufferLen); ok(packet->reportBufferLen >= expected_size, "got len %u\n", packet->reportBufferLen);
ok(!!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer); ok(!!packet->reportBuffer, "got buffer %p\n", packet->reportBuffer);
......
...@@ -2463,7 +2463,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled ...@@ -2463,7 +2463,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
else else
{ {
ok(ret, "HidD_GetInputReport failed, last error %u\n", GetLastError()); ok(ret, "HidD_GetInputReport failed, last error %u\n", GetLastError());
todo_wine ok(buffer[0] == 0x5a, "got buffer[0] %x, expected 0x5a\n", (BYTE)buffer[0]); ok(buffer[0] == 0x5a, "got buffer[0] %x, expected 0x5a\n", (BYTE)buffer[0]);
} }
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
...@@ -2685,7 +2685,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled ...@@ -2685,7 +2685,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
ret = ReadFile(file, report, caps.InputReportByteLength, &value, NULL); ret = ReadFile(file, report, caps.InputReportByteLength, &value, NULL);
ok(ret, "ReadFile failed, last error %u\n", GetLastError()); ok(ret, "ReadFile failed, last error %u\n", GetLastError());
todo_wine ok(value == (report_id ? 3 : 4), "ReadFile returned %x\n", value); ok(value == (report_id ? 3 : 4), "ReadFile returned %x\n", value);
ok(report[0] == report_id, "unexpected report data\n"); ok(report[0] == report_id, "unexpected report data\n");
overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
...@@ -2698,7 +2698,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled ...@@ -2698,7 +2698,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
ok(GetLastError() == ERROR_IO_PENDING, "ReadFile returned error %u\n", GetLastError()); ok(GetLastError() == ERROR_IO_PENDING, "ReadFile returned error %u\n", GetLastError());
ret = GetOverlappedResult(async_file, &overlapped, &value, TRUE); ret = GetOverlappedResult(async_file, &overlapped, &value, TRUE);
ok(ret, "GetOverlappedResult failed, last error %u\n", GetLastError()); ok(ret, "GetOverlappedResult failed, last error %u\n", GetLastError());
todo_wine ok(value == (report_id ? 3 : 4), "GetOverlappedResult returned length %u, expected 3\n", value); ok(value == (report_id ? 3 : 4), "GetOverlappedResult returned length %u, expected 3\n", value);
ResetEvent(overlapped.hEvent); ResetEvent(overlapped.hEvent);
memcpy(buffer, report, caps.InputReportByteLength); memcpy(buffer, report, caps.InputReportByteLength);
...@@ -2717,11 +2717,11 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled ...@@ -2717,11 +2717,11 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
/* wait for first report to be ready */ /* wait for first report to be ready */
ret = GetOverlappedResult(async_file, &overlapped, &value, TRUE); ret = GetOverlappedResult(async_file, &overlapped, &value, TRUE);
ok(ret, "GetOverlappedResult failed, last error %u\n", GetLastError()); ok(ret, "GetOverlappedResult failed, last error %u\n", GetLastError());
todo_wine ok(value == (report_id ? 3 : 4), "GetOverlappedResult returned length %u, expected 3\n", value); ok(value == (report_id ? 3 : 4), "GetOverlappedResult returned length %u, expected 3\n", value);
/* second report should be ready and the same */ /* second report should be ready and the same */
ret = GetOverlappedResult(async_file, &overlapped2, &value, FALSE); ret = GetOverlappedResult(async_file, &overlapped2, &value, FALSE);
ok(ret, "GetOverlappedResult failed, last error %u\n", GetLastError()); ok(ret, "GetOverlappedResult failed, last error %u\n", GetLastError());
todo_wine ok(value == (report_id ? 3 : 4), "GetOverlappedResult returned length %u, expected 3\n", value); ok(value == (report_id ? 3 : 4), "GetOverlappedResult returned length %u, expected 3\n", value);
ok(memcmp(report, buffer + caps.InputReportByteLength, caps.InputReportByteLength), ok(memcmp(report, buffer + caps.InputReportByteLength, caps.InputReportByteLength),
"expected different report\n"); "expected different report\n");
ok(!memcmp(report, buffer, caps.InputReportByteLength), "expected identical reports\n"); ok(!memcmp(report, buffer, caps.InputReportByteLength), "expected identical reports\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment