static NTSTATUS HID_set_to_device(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); HID_XFER_PACKET packet; NTSTATUS rc; TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.DeviceIoControl.InputBufferLength, irp->AssociatedIrp.SystemBuffer); 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, device, NULL, 0, &packet, sizeof(packet)); irp->IoStatus.u.Status = rc; if (irp->IoStatus.u.Status == STATUS_SUCCESS) irp->IoStatus.Information = irpsp->Parameters.DeviceIoControl.InputBufferLength; else irp->IoStatus.Information = 0; TRACE_(hid_report)("Result 0x%x set %li bytes\n", rc, irp->IoStatus.Information); return rc; }
NTSTATUS WINAPI HID_Device_write(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); HID_XFER_PACKET packet; NTSTATUS rc; irp->IoStatus.Information = 0; TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.Write.Length, irp->AssociatedIrp.SystemBuffer); 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)); irp->IoStatus.u.Status = rc; if (irp->IoStatus.u.Status == STATUS_SUCCESS) irp->IoStatus.Information = irpsp->Parameters.Write.Length; else irp->IoStatus.Information = 0; TRACE_(hid_report)("Result 0x%x wrote %li bytes\n", rc, irp->IoStatus.Information); IoCompleteRequest( irp, IO_NO_INCREMENT ); return rc; }
NTSTATUS WINAPI HID_Device_read(DEVICE_OBJECT *device, IRP *irp) { HID_XFER_PACKET *packet; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; UINT buffer_size = RingBuffer_GetBufferSize(ext->ring_buffer); NTSTATUS rc = STATUS_SUCCESS; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); int ptr = -1; packet = HeapAlloc(GetProcessHeap(), 0, buffer_size); ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext ); irp->IoStatus.Information = 0; RingBuffer_ReadNew(ext->ring_buffer, ptr, packet, &buffer_size); 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); 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 { BASE_DEVICE_EXTENSION *extension = device->DeviceExtension; if (extension->poll_interval) { TRACE_(hid_report)("Queue irp\n"); InsertTailList(&ext->irp_queue, &irp->Tail.Overlay.s.ListEntry); rc = STATUS_PENDING; } else { HID_XFER_PACKET packet; 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; rc = call_minidriver(IOCTL_HID_GET_INPUT_REPORT, device, NULL, 0, &packet, sizeof(packet)); if (rc == STATUS_SUCCESS) { ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0] = packet.reportId; irp->IoStatus.Information = packet.reportBufferLen + 1; irp->IoStatus.u.Status = rc; } IoCompleteRequest(irp, IO_NO_INCREMENT); } } HeapFree(GetProcessHeap(), 0, packet); return rc; }
static NTSTATUS handle_minidriver_string(DEVICE_OBJECT *device, IRP *irp, DWORD index) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); WCHAR buffer[127]; NTSTATUS status; status = call_minidriver(IOCTL_HID_GET_STRING, device, &index, sizeof(index), buffer, sizeof(buffer)); if (status == STATUS_SUCCESS) { WCHAR *out_buffer = (WCHAR*)(((BYTE*)irp->MdlAddress->StartVa) + irp->MdlAddress->ByteOffset); int length = irpsp->Parameters.DeviceIoControl.OutputBufferLength/sizeof(WCHAR); TRACE("got string %s from minidriver\n",debugstr_w(buffer)); lstrcpynW(out_buffer, buffer, length); irp->IoStatus.Information = (lstrlenW(buffer)+1) * sizeof(WCHAR); } irp->IoStatus.u.Status = status; return STATUS_SUCCESS; }
static NTSTATUS handle_minidriver_string(DEVICE_OBJECT *device, IRP *irp, SHORT index) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); WCHAR buffer[127]; NTSTATUS status; ULONG InputBuffer; InputBuffer = MAKELONG(index, 0); status = call_minidriver(IOCTL_HID_GET_STRING, device, ULongToPtr(InputBuffer), sizeof(InputBuffer), buffer, sizeof(buffer)); if (status == STATUS_SUCCESS) { WCHAR *out_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); int length = irpsp->Parameters.DeviceIoControl.OutputBufferLength/sizeof(WCHAR); TRACE("got string %s from minidriver\n",debugstr_w(buffer)); lstrcpynW(out_buffer, buffer, length); irp->IoStatus.Information = (lstrlenW(buffer)+1) * sizeof(WCHAR); } irp->IoStatus.u.Status = status; return STATUS_SUCCESS; }
static NTSTATUS HID_get_feature(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); HID_XFER_PACKET *packet; DWORD len; NTSTATUS rc = STATUS_SUCCESS; BYTE *out_buffer; irp->IoStatus.Information = 0; out_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.DeviceIoControl.OutputBufferLength, out_buffer); len = sizeof(*packet) + irpsp->Parameters.DeviceIoControl.OutputBufferLength; packet = HeapAlloc(GetProcessHeap(), 0, len); packet->reportBufferLen = irpsp->Parameters.DeviceIoControl.OutputBufferLength; packet->reportBuffer = ((BYTE*)packet) + sizeof(*packet); packet->reportId = out_buffer[0]; TRACE_(hid_report)("(id %i, len %i buffer %p)\n", packet->reportId, packet->reportBufferLen, packet->reportBuffer); rc = call_minidriver(IOCTL_HID_GET_FEATURE, device, NULL, 0, packet, sizeof(*packet)); irp->IoStatus.u.Status = rc; if (irp->IoStatus.u.Status == STATUS_SUCCESS) { irp->IoStatus.Information = packet->reportBufferLen; memcpy(out_buffer, packet->reportBuffer, packet->reportBufferLen); } else irp->IoStatus.Information = 0; TRACE_(hid_report)("Result 0x%x get %li bytes\n", rc, irp->IoStatus.Information); HeapFree(GetProcessHeap(), 0, packet); 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 <= 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; } 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 PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO) { DEVICE_OBJECT *device = NULL; NTSTATUS status; minidriver *minidriver; HID_DEVICE_ATTRIBUTES attr; BASE_DEVICE_EXTENSION *ext = NULL; HID_DESCRIPTOR descriptor; BYTE *reportDescriptor; INT i; WCHAR *PDO_id; WCHAR *id_ptr; status = get_device_id(PDO, BusQueryInstanceID, &PDO_id); if (status != STATUS_SUCCESS) { ERR("Failed to get PDO id(%x)\n",status); return status; } TRACE("PDO add device(%p:%s)\n", PDO, debugstr_w(PDO_id)); minidriver = find_minidriver(driver); status = HID_CreateDevice(PDO, &minidriver->minidriver, &device); if (status != STATUS_SUCCESS) { ERR("Failed to create HID object (%x)\n",status); HeapFree(GetProcessHeap(), 0, PDO_id); return status; } ext = device->DeviceExtension; InitializeListHead(&ext->irp_queue); TRACE("Created device %p\n",device); status = minidriver->AddDevice(minidriver->minidriver.DriverObject, device); if (status != STATUS_SUCCESS) { ERR("Minidriver AddDevice failed (%x)\n",status); HeapFree(GetProcessHeap(), 0, PDO_id); HID_DeleteDevice(&minidriver->minidriver, device); return status; } status = call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES, device, NULL, 0, &attr, sizeof(attr)); if (status != STATUS_SUCCESS) { ERR("Minidriver failed to get Attributes(%x)\n",status); HID_DeleteDevice(&minidriver->minidriver, device); HeapFree(GetProcessHeap(), 0, PDO_id); return status; } ext->information.VendorID = attr.VendorID; ext->information.ProductID = attr.ProductID; ext->information.VersionNumber = attr.VersionNumber; ext->information.Polled = minidriver->minidriver.DevicesArePolled; status = call_minidriver(IOCTL_HID_GET_DEVICE_DESCRIPTOR, device, NULL, 0, &descriptor, sizeof(descriptor)); if (status != STATUS_SUCCESS) { ERR("Cannot get Device Descriptor(%x)\n",status); HID_DeleteDevice(&minidriver->minidriver, device); HeapFree(GetProcessHeap(), 0, PDO_id); return status; } for (i = 0; i < descriptor.bNumDescriptors; i++) if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE) break; if (i >= descriptor.bNumDescriptors) { ERR("No Report Descriptor found in reply\n"); HID_DeleteDevice(&minidriver->minidriver, device); HeapFree(GetProcessHeap(), 0, PDO_id); return status; } reportDescriptor = HeapAlloc(GetProcessHeap(), 0, descriptor.DescriptorList[i].wReportLength); status = call_minidriver(IOCTL_HID_GET_REPORT_DESCRIPTOR, device, NULL, 0, reportDescriptor, descriptor.DescriptorList[i].wReportLength); if (status != STATUS_SUCCESS) { ERR("Cannot get Report Descriptor(%x)\n",status); HID_DeleteDevice(&minidriver->minidriver, device); HeapFree(GetProcessHeap(), 0, reportDescriptor); HeapFree(GetProcessHeap(), 0, PDO_id); return status; } ext->preparseData = ParseDescriptor(reportDescriptor, descriptor.DescriptorList[0].wReportLength); HeapFree(GetProcessHeap(), 0, reportDescriptor); if (!ext->preparseData) { ERR("Cannot parse Report Descriptor\n"); HID_DeleteDevice(&minidriver->minidriver, device); HeapFree(GetProcessHeap(), 0, PDO_id); return STATUS_NOT_SUPPORTED; } ext->information.DescriptorSize = ext->preparseData->dwSize; lstrcpyW(ext->instance_id, device_enumeratorW); strcatW(ext->instance_id, separator_W); /* Skip the original enumerator */ id_ptr = strchrW(PDO_id, '\\'); id_ptr++; strcatW(ext->instance_id, id_ptr); HeapFree(GetProcessHeap(), 0, PDO_id); sprintfW(ext->device_id, device_deviceid_fmtW, device_enumeratorW, ext->information.VendorID, ext->information.ProductID); HID_LinkDevice(device); ext->poll_interval = DEFAULT_POLL_INTERVAL; ext->ring_buffer = RingBuffer_Create(sizeof(HID_XFER_PACKET) + ext->preparseData->caps.InputReportByteLength); HID_StartDeviceThread(device); return STATUS_SUCCESS; }