NTSTATUS WINAPI HID_Device_ioctl(DEVICE_OBJECT *device, IRP *irp) { NTSTATUS rc = STATUS_SUCCESS; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); BASE_DEVICE_EXTENSION *extension = device->DeviceExtension; irp->IoStatus.Information = 0; TRACE("device %p ioctl(%x)\n", device, irpsp->Parameters.DeviceIoControl.IoControlCode); switch (irpsp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_HID_GET_POLL_FREQUENCY_MSEC: TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n"); if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { irp->IoStatus.u.Status = STATUS_BUFFER_OVERFLOW; irp->IoStatus.Information = 0; break; } *((ULONG*)irp->AssociatedIrp.SystemBuffer) = extension->poll_interval; irp->IoStatus.Information = sizeof(ULONG); irp->IoStatus.u.Status = STATUS_SUCCESS; break; case IOCTL_HID_SET_POLL_FREQUENCY_MSEC: { ULONG poll_interval; TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n"); if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { irp->IoStatus.u.Status = STATUS_BUFFER_TOO_SMALL; break; } poll_interval = *(ULONG *)irp->AssociatedIrp.SystemBuffer; if (poll_interval <= MAX_POLL_INTERVAL_MSEC) { extension->poll_interval = poll_interval; irp->IoStatus.u.Status = STATUS_SUCCESS; } else irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER; break; } case IOCTL_HID_GET_PRODUCT_STRING: { rc = handle_minidriver_string(device, irp, HID_STRING_ID_IPRODUCT); break; } case IOCTL_HID_GET_SERIALNUMBER_STRING: { rc = handle_minidriver_string(device, irp, HID_STRING_ID_ISERIALNUMBER); break; } case IOCTL_HID_GET_MANUFACTURER_STRING: { rc = handle_minidriver_string(device, irp, HID_STRING_ID_IMANUFACTURER); break; } case IOCTL_HID_GET_COLLECTION_INFORMATION: { rc = handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp, extension); break; } case IOCTL_HID_GET_COLLECTION_DESCRIPTOR: { rc = handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp, extension); break; } case IOCTL_HID_GET_INPUT_REPORT: { HID_XFER_PACKET *packet; UINT packet_size = sizeof(*packet) + irpsp->Parameters.DeviceIoControl.OutputBufferLength; BYTE *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); ULONG out_length; packet = HeapAlloc(GetProcessHeap(), 0, packet_size); if (extension->preparseData->InputReports[0].reportID) packet->reportId = buffer[0]; else packet->reportId = 0; packet->reportBuffer = (BYTE *)packet + sizeof(*packet); packet->reportBufferLen = irpsp->Parameters.DeviceIoControl.OutputBufferLength - 1; rc = call_minidriver(IOCTL_HID_GET_INPUT_REPORT, device, NULL, 0, packet, sizeof(*packet)); if (rc == STATUS_SUCCESS) { rc = copy_packet_into_buffer(packet, buffer, irpsp->Parameters.DeviceIoControl.OutputBufferLength, &out_length); irp->IoStatus.Information = out_length; } else irp->IoStatus.Information = 0; irp->IoStatus.u.Status = rc; HeapFree(GetProcessHeap(), 0, packet); break; } case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS: { irp->IoStatus.Information = 0; if (irpsp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG)) { irp->IoStatus.u.Status = rc = STATUS_BUFFER_OVERFLOW; } else { rc = RingBuffer_SetSize(extension->ring_buffer, *(ULONG*)irp->AssociatedIrp.SystemBuffer); irp->IoStatus.u.Status = rc; } break; } case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS: { if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { irp->IoStatus.u.Status = rc = STATUS_BUFFER_TOO_SMALL; } else { *(ULONG*)irp->AssociatedIrp.SystemBuffer = RingBuffer_GetSize(extension->ring_buffer); rc = irp->IoStatus.u.Status = STATUS_SUCCESS; } break; } case IOCTL_HID_GET_FEATURE: rc = HID_get_feature(device, irp); break; case IOCTL_HID_SET_FEATURE: case IOCTL_HID_SET_OUTPUT_REPORT: rc = HID_set_to_device(device, irp); break; default: { ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode; FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n", code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3); irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; rc = STATUS_UNSUCCESSFUL; break; } } if (rc != STATUS_PENDING) IoCompleteRequest( irp, IO_NO_INCREMENT ); return rc; }
NTSTATUS WINAPI HID_Device_ioctl(DEVICE_OBJECT *device, IRP *irp) { NTSTATUS rc = STATUS_SUCCESS; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); BASE_DEVICE_EXTENSION *extension = device->DeviceExtension; irp->IoStatus.Information = 0; TRACE("device %p ioctl(%x)\n", device, irpsp->Parameters.DeviceIoControl.IoControlCode); switch (irpsp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_HID_GET_POLL_FREQUENCY_MSEC: TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n"); if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { irp->IoStatus.u.Status = STATUS_BUFFER_OVERFLOW; irp->IoStatus.Information = 0; break; } *((ULONG*)irp->AssociatedIrp.SystemBuffer) = extension->poll_interval; irp->IoStatus.Information = sizeof(ULONG); irp->IoStatus.u.Status = STATUS_SUCCESS; break; case IOCTL_HID_SET_POLL_FREQUENCY_MSEC: { ULONG poll_interval; TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n"); if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { irp->IoStatus.u.Status = STATUS_BUFFER_TOO_SMALL; break; } poll_interval = *(ULONG *)irp->AssociatedIrp.SystemBuffer; if (poll_interval == 0) FIXME("Handle opportunistic reads\n"); else if (poll_interval <= MAX_POLL_INTERVAL_MSEC) { extension->poll_interval = poll_interval; irp->IoStatus.u.Status = STATUS_SUCCESS; } else irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER; break; } case IOCTL_HID_GET_PRODUCT_STRING: { rc = handle_minidriver_string(device, irp, HID_STRING_ID_IPRODUCT); break; } case IOCTL_HID_GET_MANUFACTURER_STRING: { rc = handle_minidriver_string(device, irp, HID_STRING_ID_IMANUFACTURER); break; } case IOCTL_HID_GET_COLLECTION_INFORMATION: { rc = handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp, extension); break; } case IOCTL_HID_GET_COLLECTION_DESCRIPTOR: { rc = handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp, extension); break; } case IOCTL_HID_GET_INPUT_REPORT: { HID_XFER_PACKET packet; BYTE* buffer = ((BYTE*)irp->MdlAddress->StartVa) + irp->MdlAddress->ByteOffset; if (extension->preparseData->InputReports[0].reportID) packet.reportId = buffer[0]; else packet.reportId = 0; packet.reportBuffer = buffer; packet.reportBufferLen = irpsp->Parameters.DeviceIoControl.OutputBufferLength; call_minidriver(IOCTL_HID_GET_INPUT_REPORT, device, NULL, 0, &packet, sizeof(packet)); irp->IoStatus.Information = packet.reportBufferLen; irp->IoStatus.u.Status = STATUS_SUCCESS; break; } case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS: { irp->IoStatus.Information = 0; if (irpsp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG)) { irp->IoStatus.u.Status = rc = STATUS_BUFFER_OVERFLOW; } else { rc = RingBuffer_SetSize(extension->ring_buffer, *(ULONG*)irp->AssociatedIrp.SystemBuffer); irp->IoStatus.u.Status = rc; } break; } case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS: { if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { irp->IoStatus.u.Status = rc = STATUS_BUFFER_TOO_SMALL; } else { *(ULONG*)irp->AssociatedIrp.SystemBuffer = RingBuffer_GetSize(extension->ring_buffer); rc = irp->IoStatus.u.Status = STATUS_SUCCESS; } break; } default: { ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode; FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n", code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3); irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED; rc = STATUS_UNSUCCESSFUL; break; } } if (rc != STATUS_PENDING) IoCompleteRequest( irp, IO_NO_INCREMENT ); return rc; }