From d0039106dea1f4f6e6d762f564c8f12364a2db01 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Tue, 29 Nov 2016 07:58:27 -0600 Subject: [PATCH] hidclass: All reports read or written to user space lead with a reportId. Signed-off-by: Aric Stewart Signed-off-by: Alexandre Julliard --- dlls/hidclass.sys/descriptor.c | 31 +++-------- dlls/hidclass.sys/device.c | 94 +++++++++++++++++++++++----------- dlls/winebus.sys/bus_udev.c | 38 +++++++++++++- 3 files changed, 107 insertions(+), 56 deletions(-) diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 9a80f68ae36..98055113c20 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -919,10 +919,8 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData( new_report(wine_report, input_features[0]); data->dwInputReportCount++; - if (input_features[0]->caps.ReportID != 0) - bitOffset = 8; - else - bitOffset = 0; + /* Room for the reportID */ + bitOffset = 8; for (i = 0; i < i_count; i++) { @@ -933,10 +931,7 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData( new_report(wine_report, input_features[i]); data->dwInputReportCount++; bitLength = max(bitOffset, bitLength); - if (input_features[i]->caps.ReportID != 0) - bitOffset = 8; - else - bitOffset = 0; + bitOffset = 8; } build_elements(wine_report, input_features[i], &bitOffset); count_elements(input_features[i], &data->caps.NumberInputButtonCaps, @@ -954,10 +949,7 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData( data->dwOutputReportOffset = (BYTE*)wine_report - (BYTE*)data->InputReports; new_report(wine_report, output_features[0]); data->dwOutputReportCount++; - if (output_features[0]->caps.ReportID != 0) - bitOffset = 8; - else - bitOffset = 0; + bitOffset = 8; for (i = 0; i < o_count; i++) { @@ -968,10 +960,7 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData( new_report(wine_report, output_features[i]); data->dwOutputReportCount++; bitLength = max(bitOffset, bitLength); - if (output_features[0]->caps.ReportID != 0) - bitOffset = 8; - else - bitOffset = 0; + bitOffset = 8; } build_elements(wine_report, output_features[i], &bitOffset); count_elements(output_features[i], &data->caps.NumberOutputButtonCaps, @@ -989,10 +978,7 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData( data->dwFeatureReportOffset = (BYTE*)wine_report - (BYTE*)data->InputReports; new_report(wine_report, feature_features[0]); data->dwFeatureReportCount++; - if (feature_features[0]->caps.ReportID != 0) - bitOffset = 8; - else - bitOffset = 0; + bitOffset = 8; for (i = 0; i < f_count; i++) { @@ -1003,10 +989,7 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData( new_report(wine_report, feature_features[i]); data->dwFeatureReportCount++; bitLength = max(bitOffset, bitLength); - if (feature_features[0]->caps.ReportID != 0) - bitOffset = 8; - else - bitOffset = 0; + bitOffset = 8; } build_elements(wine_report, feature_features[i], &bitOffset); count_elements(feature_features[i], &data->caps.NumberFeatureButtonCaps, diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 5dd5ebb9ba6..b241016e725 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -197,6 +197,32 @@ void HID_DeleteDevice(HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT *device IoDeleteDevice(device); } +static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, ULONG buffer_length, ULONG *out_length) +{ + BOOL zero_id = (packet->reportId == 0); + + *out_length = 0; + + if ((zero_id && buffer_length > packet->reportBufferLen) || + (!zero_id && buffer_length >= packet->reportBufferLen)) + { + if (packet->reportId != 0) + { + memcpy(buffer, packet->reportBuffer, packet->reportBufferLen); + *out_length = packet->reportBufferLen; + } + else + { + buffer[0] = 0; + memcpy(&buffer[1], packet->reportBuffer, packet->reportBufferLen); + *out_length = packet->reportBufferLen + 1; + } + return STATUS_SUCCESS; + } + else + return STATUS_BUFFER_OVERFLOW; +} + static void HID_Device_processQueue(DEVICE_OBJECT *device) { LIST_ENTRY *entry; @@ -217,20 +243,14 @@ static void HID_Device_processQueue(DEVICE_OBJECT *device) RingBuffer_Read(ext->ring_buffer, ptr, packet, &buffer_size); if (buffer_size) { + NTSTATUS rc; + ULONG out_length; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); packet->reportBuffer = (BYTE *)packet + sizeof(*packet); 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; - } + rc = copy_packet_into_buffer(packet, irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.Read.Length, &out_length); + irp->IoStatus.u.Status = rc; + irp->IoStatus.Information = out_length; } else { @@ -331,7 +351,10 @@ static DWORD CALLBACK hid_device_thread(void *args) if (!exit_now && irp->IoStatus.u.Status == STATUS_SUCCESS) { packet->reportBufferLen = irp->IoStatus.Information; - packet->reportId = packet->reportBuffer[0]; + if (ext->preparseData->InputReports[0].reportID) + packet->reportId = packet->reportBuffer[0]; + else + packet->reportId = 0; RingBuffer_Write(ext->ring_buffer, packet); HID_Device_processQueue(device); } @@ -461,9 +484,17 @@ static NTSTATUS HID_set_to_device(DEVICE_OBJECT *device, IRP *irp) NTSTATUS rc; TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.DeviceIoControl.InputBufferLength, irp->AssociatedIrp.SystemBuffer); - packet.reportBuffer = irp->AssociatedIrp.SystemBuffer; - packet.reportId = ((char*)irp->AssociatedIrp.SystemBuffer)[0]; - packet.reportBufferLen = irpsp->Parameters.DeviceIoControl.InputBufferLength; + packet.reportId = ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0]; + if (packet.reportId == 0) + { + packet.reportBuffer = &((BYTE*)irp->AssociatedIrp.SystemBuffer)[1]; + packet.reportBufferLen = irpsp->Parameters.DeviceIoControl.InputBufferLength - 1; + } + else + { + packet.reportBuffer = irp->AssociatedIrp.SystemBuffer; + packet.reportBufferLen = irpsp->Parameters.DeviceIoControl.InputBufferLength; + } TRACE_(hid_report)("(id %i, len %i buffer %p)\n", packet.reportId, packet.reportBufferLen, packet.reportBuffer); rc = call_minidriver(irpsp->Parameters.DeviceIoControl.IoControlCode, @@ -636,20 +667,15 @@ NTSTATUS WINAPI HID_Device_read(DEVICE_OBJECT *device, IRP *irp) if (buffer_size) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + NTSTATUS rc; + ULONG out_length; packet->reportBuffer = (BYTE *)packet + sizeof(*packet); TRACE_(hid_report)("Got Packet %p %i\n", packet->reportBuffer, packet->reportBufferLen); - 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; - } - IoCompleteRequest( irp, IO_NO_INCREMENT ); + + rc = copy_packet_into_buffer(packet, irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.Read.Length, &out_length); + irp->IoStatus.Information = out_length; + irp->IoStatus.u.Status = rc; + IoCompleteRequest(irp, IO_NO_INCREMENT); } else { @@ -671,9 +697,17 @@ NTSTATUS WINAPI HID_Device_write(DEVICE_OBJECT *device, IRP *irp) irp->IoStatus.Information = 0; TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.Write.Length, irp->AssociatedIrp.SystemBuffer); - packet.reportBuffer = irp->AssociatedIrp.SystemBuffer; - packet.reportId = ((char*)irp->AssociatedIrp.SystemBuffer)[0]; - packet.reportBufferLen = irpsp->Parameters.Write.Length; + packet.reportId = ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0]; + if (packet.reportId == 0) + { + packet.reportBuffer = &((BYTE*)irp->AssociatedIrp.SystemBuffer)[1]; + packet.reportBufferLen = irpsp->Parameters.Write.Length - 1; + } + else + { + packet.reportBuffer = irp->AssociatedIrp.SystemBuffer; + packet.reportBufferLen = irpsp->Parameters.Write.Length; + } TRACE_(hid_report)("(id %i, len %i buffer %p)\n", packet.reportId, packet.reportBufferLen, packet.reportBuffer); rc = call_minidriver(IOCTL_HID_WRITE_REPORT, device, NULL, 0, &packet, sizeof(packet)); diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 6cfbdb8f905..515ae707045 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -288,7 +288,23 @@ static NTSTATUS hidraw_set_output_report(DEVICE_OBJECT *device, UCHAR id, BYTE * { struct platform_private* ext = impl_from_DEVICE_OBJECT(device); ssize_t rc; - rc = write(ext->device_fd, report, length); + + if (id != 0) + rc = write(ext->device_fd, report, length); + else + { + BYTE report_buffer[1024]; + + if (length + 1 > sizeof(report_buffer)) + { + ERR("Output report buffer too small\n"); + return STATUS_UNSUCCESSFUL; + } + + report_buffer[0] = 0; + memcpy(&report_buffer[1], report, length); + rc = write(ext->device_fd, report_buffer, length + 1); + } if (rc > 0) { *written = rc; @@ -306,6 +322,7 @@ static NTSTATUS hidraw_get_feature_report(DEVICE_OBJECT *device, UCHAR id, BYTE #ifdef HAVE_LINUX_HIDRAW_H int rc; struct platform_private* ext = impl_from_DEVICE_OBJECT(device); + report[0] = id; length = min(length, 0x1fff); rc = ioctl(ext->device_fd, HIDIOCGFEATURE(length), report); if (rc >= 0) @@ -329,8 +346,25 @@ static NTSTATUS hidraw_set_feature_report(DEVICE_OBJECT *device, UCHAR id, BYTE #ifdef HAVE_LINUX_HIDRAW_H int rc; struct platform_private* ext = impl_from_DEVICE_OBJECT(device); + BYTE *feature_buffer; + BYTE buffer[1024]; + + if (id == 0) + { + if (length + 1 > sizeof(feature_buffer)) + { + ERR("Output feature buffer too small\n"); + return STATUS_UNSUCCESSFUL; + } + buffer[0] = 0; + memcpy(&buffer[1], report, length); + feature_buffer = buffer; + length = length + 1; + } + else + feature_buffer = report; length = min(length, 0x1fff); - rc = ioctl(ext->device_fd, HIDIOCSFEATURE(length), report); + rc = ioctl(ext->device_fd, HIDIOCSFEATURE(length), feature_buffer); if (rc >= 0) { *written = rc;