makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / hidclass.sys / device.c
blob0e905c8322f1c332a3483a7635b61adc6a313e9a
1 /*
2 * HIDClass device functions
4 * Copyright (C) 2015 Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24 #include "hid.h"
25 #include "winreg.h"
26 #include "winuser.h"
27 #include "setupapi.h"
29 #include "wine/debug.h"
30 #include "ddk/hidsdi.h"
31 #include "ddk/hidtypes.h"
32 #include "ddk/wdm.h"
34 #include "initguid.h"
35 #include "devguid.h"
36 #include "ntddmou.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(hid);
39 WINE_DECLARE_DEBUG_CHANNEL(hid_report);
41 static const WCHAR device_name_fmtW[] = {'\\','D','e','v','i','c','e',
42 '\\','H','I','D','#','%','p','&','%','p',0};
44 NTSTATUS HID_CreateDevice(DEVICE_OBJECT *native_device, HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT **device)
46 WCHAR dev_name[255];
47 UNICODE_STRING nameW;
48 NTSTATUS status;
49 BASE_DEVICE_EXTENSION *ext;
51 swprintf(dev_name, ARRAY_SIZE(dev_name), device_name_fmtW, driver->DriverObject, native_device);
52 RtlInitUnicodeString( &nameW, dev_name );
54 TRACE("Create base hid device %s\n", debugstr_w(dev_name));
56 status = IoCreateDevice(driver->DriverObject, driver->DeviceExtensionSize + sizeof(BASE_DEVICE_EXTENSION), &nameW, 0, 0, FALSE, device);
57 if (status)
59 FIXME( "failed to create device error %x\n", status );
60 return status;
63 ext = (*device)->DeviceExtension;
65 ext->deviceExtension.MiniDeviceExtension = ext + 1;
66 ext->deviceExtension.PhysicalDeviceObject = *device;
67 ext->deviceExtension.NextDeviceObject = native_device;
68 ext->device_name = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(dev_name) + 1) * sizeof(WCHAR));
69 lstrcpyW(ext->device_name, dev_name);
70 ext->link_name.Buffer = NULL;
72 IoAttachDeviceToDeviceStack(*device, native_device);
74 return STATUS_SUCCESS;
77 NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device)
79 static const WCHAR backslashW[] = {'\\',0};
80 WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
81 SP_DEVINFO_DATA Data;
82 UNICODE_STRING nameW;
83 NTSTATUS status;
84 HDEVINFO devinfo;
85 GUID hidGuid;
86 BASE_DEVICE_EXTENSION *ext;
88 HidD_GetHidGuid(&hidGuid);
89 ext = device->DeviceExtension;
91 RtlInitUnicodeString( &nameW, ext->device_name);
93 lstrcpyW(device_instance_id, ext->device_id);
94 lstrcatW(device_instance_id, backslashW);
95 lstrcatW(device_instance_id, ext->instance_id);
97 devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_HIDCLASS, NULL);
98 if (devinfo == INVALID_HANDLE_VALUE)
100 FIXME( "failed to get ClassDevs %x\n", GetLastError());
101 return STATUS_UNSUCCESSFUL;
103 Data.cbSize = sizeof(Data);
104 if (SetupDiCreateDeviceInfoW(devinfo, device_instance_id, &GUID_DEVCLASS_HIDCLASS, NULL, NULL, DICD_INHERIT_CLASSDRVS, &Data))
106 if (!SetupDiRegisterDeviceInfo(devinfo, &Data, 0, NULL, NULL, NULL))
108 FIXME( "failed to register device info %x\n", GetLastError());
109 goto error;
112 else if (GetLastError() != ERROR_DEVINST_ALREADY_EXISTS)
114 FIXME( "failed to create device info %x\n", GetLastError());
115 goto error;
117 SetupDiDestroyDeviceInfoList(devinfo);
119 status = IoRegisterDeviceInterface(device, &hidGuid, NULL, &ext->link_name);
120 if (status != STATUS_SUCCESS)
122 FIXME( "failed to register device interface %x\n", status );
123 return status;
126 /* FIXME: This should probably be done in mouhid.sys. */
127 if (ext->preparseData->caps.UsagePage == HID_USAGE_PAGE_GENERIC
128 && ext->preparseData->caps.Usage == HID_USAGE_GENERIC_MOUSE)
130 if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_MOUSE, NULL, &ext->mouse_link_name))
131 ext->is_mouse = TRUE;
134 return STATUS_SUCCESS;
136 error:
137 SetupDiDestroyDeviceInfoList(devinfo);
138 return STATUS_UNSUCCESSFUL;
141 static IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext)
143 LIST_ENTRY *entry;
144 KIRQL old_irql;
145 IRP *irp = NULL;
147 KeAcquireSpinLock(&ext->irp_queue_lock, &old_irql);
149 while (!irp && (entry = RemoveHeadList(&ext->irp_queue)) != &ext->irp_queue)
151 irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.s.ListEntry);
152 if (!IoSetCancelRoutine(irp, NULL))
154 /* cancel routine is already cleared, meaning that it was called. let it handle completion. */
155 InitializeListHead(&irp->Tail.Overlay.s.ListEntry);
156 irp = NULL;
160 KeReleaseSpinLock(&ext->irp_queue_lock, old_irql);
161 return irp;
164 static void WINAPI read_cancel_routine(DEVICE_OBJECT *device, IRP *irp)
166 BASE_DEVICE_EXTENSION *ext;
167 KIRQL old_irql;
169 TRACE("cancel %p IRP on device %p\n", irp, device);
171 ext = device->DeviceExtension;
173 IoReleaseCancelSpinLock(irp->CancelIrql);
175 KeAcquireSpinLock(&ext->irp_queue_lock, &old_irql);
177 RemoveEntryList(&irp->Tail.Overlay.s.ListEntry);
179 KeReleaseSpinLock(&ext->irp_queue_lock, old_irql);
181 irp->IoStatus.u.Status = STATUS_CANCELLED;
182 irp->IoStatus.Information = 0;
183 IoCompleteRequest(irp, IO_NO_INCREMENT);
186 void HID_DeleteDevice(DEVICE_OBJECT *device)
188 BASE_DEVICE_EXTENSION *ext;
189 IRP *irp;
191 ext = device->DeviceExtension;
193 if (ext->thread)
195 SetEvent(ext->halt_event);
196 WaitForSingleObject(ext->thread, INFINITE);
198 CloseHandle(ext->halt_event);
200 HeapFree(GetProcessHeap(), 0, ext->preparseData);
201 if (ext->ring_buffer)
202 RingBuffer_Destroy(ext->ring_buffer);
204 while((irp = pop_irp_from_queue(ext)))
206 irp->IoStatus.u.Status = STATUS_DEVICE_REMOVED;
207 IoCompleteRequest(irp, IO_NO_INCREMENT);
210 TRACE("Delete device(%p) %s\n", device, debugstr_w(ext->device_name));
211 HeapFree(GetProcessHeap(), 0, ext->device_name);
212 RtlFreeUnicodeString(&ext->link_name);
214 IoDetachDevice(ext->deviceExtension.NextDeviceObject);
215 IoDeleteDevice(device);
218 static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, ULONG buffer_length, ULONG *out_length)
220 BOOL zero_id = (packet->reportId == 0);
222 *out_length = 0;
224 if ((zero_id && buffer_length > packet->reportBufferLen) ||
225 (!zero_id && buffer_length >= packet->reportBufferLen))
227 if (packet->reportId != 0)
229 memcpy(buffer, packet->reportBuffer, packet->reportBufferLen);
230 *out_length = packet->reportBufferLen;
232 else
234 buffer[0] = 0;
235 memcpy(&buffer[1], packet->reportBuffer, packet->reportBufferLen);
236 *out_length = packet->reportBufferLen + 1;
238 return STATUS_SUCCESS;
240 else
241 return STATUS_BUFFER_OVERFLOW;
244 static void HID_Device_processQueue(DEVICE_OBJECT *device)
246 IRP *irp;
247 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
248 UINT buffer_size = RingBuffer_GetBufferSize(ext->ring_buffer);
249 HID_XFER_PACKET *packet;
251 packet = HeapAlloc(GetProcessHeap(), 0, buffer_size);
253 while((irp = pop_irp_from_queue(ext)))
255 int ptr;
256 ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
258 RingBuffer_Read(ext->ring_buffer, ptr, packet, &buffer_size);
259 if (buffer_size)
261 NTSTATUS rc;
262 ULONG out_length;
263 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
264 packet->reportBuffer = (BYTE *)packet + sizeof(*packet);
265 TRACE_(hid_report)("Processing Request (%i)\n",ptr);
266 rc = copy_packet_into_buffer(packet, irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.Read.Length, &out_length);
267 irp->IoStatus.u.Status = rc;
268 irp->IoStatus.Information = out_length;
270 else
272 irp->IoStatus.Information = 0;
273 irp->IoStatus.u.Status = STATUS_UNSUCCESSFUL;
275 IoCompleteRequest( irp, IO_NO_INCREMENT );
277 HeapFree(GetProcessHeap(), 0, packet);
280 static NTSTATUS WINAPI read_Completion(DEVICE_OBJECT *deviceObject, IRP *irp, void *context)
282 HANDLE event = context;
283 SetEvent(event);
284 return STATUS_MORE_PROCESSING_REQUIRED;
287 static DWORD CALLBACK hid_device_thread(void *args)
289 DEVICE_OBJECT *device = (DEVICE_OBJECT*)args;
291 IRP *irp;
292 IO_STATUS_BLOCK irp_status;
293 HID_XFER_PACKET *packet;
294 DWORD rc;
295 HANDLE events[2];
296 NTSTATUS ntrc;
298 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
299 events[0] = CreateEventA(NULL, TRUE, FALSE, NULL);
300 events[1] = ext->halt_event;
302 packet = HeapAlloc(GetProcessHeap(), 0, sizeof(*packet) + ext->preparseData->caps.InputReportByteLength);
303 packet->reportBuffer = (BYTE *)packet + sizeof(*packet);
305 if (ext->information.Polled)
307 while(1)
309 ResetEvent(events[0]);
311 packet->reportBufferLen = ext->preparseData->caps.InputReportByteLength;
312 packet->reportId = 0;
314 irp = IoBuildDeviceIoControlRequest(IOCTL_HID_GET_INPUT_REPORT,
315 device, NULL, 0, packet, sizeof(*packet), TRUE, NULL,
316 &irp_status);
318 IoSetCompletionRoutine(irp, read_Completion, events[0], TRUE, TRUE, TRUE);
319 ntrc = IoCallDriver(device, irp);
321 if (ntrc == STATUS_PENDING)
322 WaitForMultipleObjects(2, events, FALSE, INFINITE);
324 if (irp->IoStatus.u.Status == STATUS_SUCCESS)
326 RingBuffer_Write(ext->ring_buffer, packet);
327 HID_Device_processQueue(device);
330 IoCompleteRequest(irp, IO_NO_INCREMENT );
332 rc = WaitForSingleObject(ext->halt_event, ext->poll_interval ? ext->poll_interval : DEFAULT_POLL_INTERVAL);
334 if (rc == WAIT_OBJECT_0)
335 break;
336 else if (rc != WAIT_TIMEOUT)
337 ERR("Wait returned unexpected value %x\n",rc);
340 else
342 INT exit_now = FALSE;
344 while(1)
346 ResetEvent(events[0]);
348 irp = IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT,
349 device, NULL, 0, packet->reportBuffer,
350 ext->preparseData->caps.InputReportByteLength, TRUE, NULL,
351 &irp_status);
353 IoSetCompletionRoutine(irp, read_Completion, events[0], TRUE, TRUE, TRUE);
354 ntrc = IoCallDriver(device, irp);
356 if (ntrc == STATUS_PENDING)
358 WaitForMultipleObjects(2, events, FALSE, INFINITE);
361 rc = WaitForSingleObject(ext->halt_event, 0);
362 if (rc == WAIT_OBJECT_0)
363 exit_now = TRUE;
365 if (!exit_now && irp->IoStatus.u.Status == STATUS_SUCCESS)
367 packet->reportBufferLen = irp->IoStatus.Information;
368 if (ext->preparseData->reports[0].reportID)
369 packet->reportId = packet->reportBuffer[0];
370 else
371 packet->reportId = 0;
372 RingBuffer_Write(ext->ring_buffer, packet);
373 HID_Device_processQueue(device);
376 IoCompleteRequest(irp, IO_NO_INCREMENT );
378 if (exit_now)
379 break;
383 /* FIXME: releasing packet requires IRP cancellation support */
384 CloseHandle(events[0]);
386 TRACE("Device thread exiting\n");
387 return 1;
390 void HID_StartDeviceThread(DEVICE_OBJECT *device)
392 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
393 ext->halt_event = CreateEventA(NULL, TRUE, FALSE, NULL);
394 ext->thread = CreateThread(NULL, 0, hid_device_thread, device, 0, NULL);
397 static NTSTATUS handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP *irp, BASE_DEVICE_EXTENSION *base)
399 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
400 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
402 irp->IoStatus.u.Status = STATUS_BUFFER_OVERFLOW;
403 irp->IoStatus.Information = 0;
405 else
407 memcpy(irp->AssociatedIrp.SystemBuffer, &base->information, sizeof(HID_COLLECTION_INFORMATION));
408 irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
409 irp->IoStatus.u.Status = STATUS_SUCCESS;
411 return STATUS_SUCCESS;
414 static NTSTATUS handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(IRP *irp, BASE_DEVICE_EXTENSION *base)
416 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
418 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < base->preparseData->dwSize)
420 irp->IoStatus.u.Status = STATUS_INVALID_BUFFER_SIZE;
421 irp->IoStatus.Information = 0;
423 else
425 memcpy(irp->UserBuffer, base->preparseData, base->preparseData->dwSize);
426 irp->IoStatus.Information = base->preparseData->dwSize;
427 irp->IoStatus.u.Status = STATUS_SUCCESS;
429 return STATUS_SUCCESS;
432 static NTSTATUS handle_minidriver_string(DEVICE_OBJECT *device, IRP *irp, SHORT index)
434 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
435 WCHAR buffer[127];
436 NTSTATUS status;
437 ULONG InputBuffer;
439 InputBuffer = MAKELONG(index, 0);
440 status = call_minidriver(IOCTL_HID_GET_STRING, device, ULongToPtr(InputBuffer), sizeof(InputBuffer), buffer, sizeof(buffer));
442 if (status == STATUS_SUCCESS)
444 WCHAR *out_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
445 int length = irpsp->Parameters.DeviceIoControl.OutputBufferLength/sizeof(WCHAR);
446 TRACE("got string %s from minidriver\n",debugstr_w(buffer));
447 lstrcpynW(out_buffer, buffer, length);
448 irp->IoStatus.Information = (lstrlenW(buffer)+1) * sizeof(WCHAR);
450 irp->IoStatus.u.Status = status;
452 return STATUS_SUCCESS;
455 static NTSTATUS HID_get_feature(DEVICE_OBJECT *device, IRP *irp)
457 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
458 HID_XFER_PACKET *packet;
459 DWORD len;
460 NTSTATUS rc = STATUS_SUCCESS;
461 BYTE *out_buffer;
463 irp->IoStatus.Information = 0;
465 out_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
466 TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.DeviceIoControl.OutputBufferLength, out_buffer);
468 len = sizeof(*packet) + irpsp->Parameters.DeviceIoControl.OutputBufferLength;
469 packet = HeapAlloc(GetProcessHeap(), 0, len);
470 packet->reportBufferLen = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
471 packet->reportBuffer = ((BYTE*)packet) + sizeof(*packet);
472 packet->reportId = out_buffer[0];
474 TRACE_(hid_report)("(id %i, len %i buffer %p)\n", packet->reportId, packet->reportBufferLen, packet->reportBuffer);
476 rc = call_minidriver(IOCTL_HID_GET_FEATURE, device, NULL, 0, packet, sizeof(*packet));
478 irp->IoStatus.u.Status = rc;
479 if (irp->IoStatus.u.Status == STATUS_SUCCESS)
481 irp->IoStatus.Information = packet->reportBufferLen;
482 memcpy(out_buffer, packet->reportBuffer, packet->reportBufferLen);
484 else
485 irp->IoStatus.Information = 0;
487 TRACE_(hid_report)("Result 0x%x get %li bytes\n", rc, irp->IoStatus.Information);
489 HeapFree(GetProcessHeap(), 0, packet);
491 return rc;
494 static NTSTATUS HID_set_to_device(DEVICE_OBJECT *device, IRP *irp)
496 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
497 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
498 HID_XFER_PACKET packet;
499 ULONG max_len;
500 NTSTATUS rc;
502 TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.DeviceIoControl.InputBufferLength, irp->AssociatedIrp.SystemBuffer);
503 packet.reportId = ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0];
504 if (packet.reportId == 0)
506 packet.reportBuffer = &((BYTE*)irp->AssociatedIrp.SystemBuffer)[1];
507 packet.reportBufferLen = irpsp->Parameters.DeviceIoControl.InputBufferLength - 1;
508 if (irpsp->Parameters.DeviceIoControl.IoControlCode == IOCTL_HID_SET_FEATURE)
509 max_len = ext->preparseData->caps.FeatureReportByteLength;
510 else
511 max_len = ext->preparseData->caps.OutputReportByteLength;
513 else
515 packet.reportBuffer = irp->AssociatedIrp.SystemBuffer;
516 packet.reportBufferLen = irpsp->Parameters.DeviceIoControl.InputBufferLength;
517 if (irpsp->Parameters.DeviceIoControl.IoControlCode == IOCTL_HID_SET_FEATURE)
518 max_len = (ext->preparseData->reports[ext->preparseData->reportIdx[HidP_Feature][packet.reportId]].bitSize + 7) / 8;
519 else
520 max_len = (ext->preparseData->reports[ext->preparseData->reportIdx[HidP_Output][packet.reportId]].bitSize + 7) / 8;
522 if (packet.reportBufferLen > max_len)
523 packet.reportBufferLen = max_len;
525 TRACE_(hid_report)("(id %i, len %i buffer %p)\n", packet.reportId, packet.reportBufferLen, packet.reportBuffer);
527 rc = call_minidriver(irpsp->Parameters.DeviceIoControl.IoControlCode,
528 device, NULL, 0, &packet, sizeof(packet));
530 irp->IoStatus.u.Status = rc;
531 if (irp->IoStatus.u.Status == STATUS_SUCCESS)
532 irp->IoStatus.Information = irpsp->Parameters.DeviceIoControl.InputBufferLength;
533 else
534 irp->IoStatus.Information = 0;
536 TRACE_(hid_report)("Result 0x%x set %li bytes\n", rc, irp->IoStatus.Information);
538 return rc;
541 NTSTATUS WINAPI HID_Device_ioctl(DEVICE_OBJECT *device, IRP *irp)
543 NTSTATUS rc = STATUS_SUCCESS;
544 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
545 BASE_DEVICE_EXTENSION *extension = device->DeviceExtension;
547 irp->IoStatus.Information = 0;
549 TRACE("device %p ioctl(%x)\n", device, irpsp->Parameters.DeviceIoControl.IoControlCode);
551 switch (irpsp->Parameters.DeviceIoControl.IoControlCode)
553 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC:
554 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
555 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
557 irp->IoStatus.u.Status = STATUS_BUFFER_OVERFLOW;
558 irp->IoStatus.Information = 0;
559 break;
561 *((ULONG*)irp->AssociatedIrp.SystemBuffer) = extension->poll_interval;
562 irp->IoStatus.Information = sizeof(ULONG);
563 irp->IoStatus.u.Status = STATUS_SUCCESS;
564 break;
565 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC:
567 ULONG poll_interval;
568 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
569 if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
571 irp->IoStatus.u.Status = STATUS_BUFFER_TOO_SMALL;
572 break;
574 poll_interval = *(ULONG *)irp->AssociatedIrp.SystemBuffer;
575 if (poll_interval <= MAX_POLL_INTERVAL_MSEC)
577 extension->poll_interval = poll_interval;
578 irp->IoStatus.u.Status = STATUS_SUCCESS;
580 else
581 irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
582 break;
584 case IOCTL_HID_GET_PRODUCT_STRING:
586 rc = handle_minidriver_string(device, irp, HID_STRING_ID_IPRODUCT);
587 break;
589 case IOCTL_HID_GET_SERIALNUMBER_STRING:
591 rc = handle_minidriver_string(device, irp, HID_STRING_ID_ISERIALNUMBER);
592 break;
594 case IOCTL_HID_GET_MANUFACTURER_STRING:
596 rc = handle_minidriver_string(device, irp, HID_STRING_ID_IMANUFACTURER);
597 break;
599 case IOCTL_HID_GET_COLLECTION_INFORMATION:
601 rc = handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp, extension);
602 break;
604 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
606 rc = handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp, extension);
607 break;
609 case IOCTL_HID_GET_INPUT_REPORT:
611 HID_XFER_PACKET *packet;
612 UINT packet_size = sizeof(*packet) + irpsp->Parameters.DeviceIoControl.OutputBufferLength;
613 BYTE *buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
614 ULONG out_length;
616 packet = HeapAlloc(GetProcessHeap(), 0, packet_size);
618 if (extension->preparseData->reports[0].reportID)
619 packet->reportId = buffer[0];
620 else
621 packet->reportId = 0;
622 packet->reportBuffer = (BYTE *)packet + sizeof(*packet);
623 packet->reportBufferLen = irpsp->Parameters.DeviceIoControl.OutputBufferLength - 1;
625 rc = call_minidriver(IOCTL_HID_GET_INPUT_REPORT, device, NULL, 0, packet, sizeof(*packet));
626 if (rc == STATUS_SUCCESS)
628 rc = copy_packet_into_buffer(packet, buffer, irpsp->Parameters.DeviceIoControl.OutputBufferLength, &out_length);
629 irp->IoStatus.Information = out_length;
631 else
632 irp->IoStatus.Information = 0;
633 irp->IoStatus.u.Status = rc;
634 HeapFree(GetProcessHeap(), 0, packet);
635 break;
637 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS:
639 irp->IoStatus.Information = 0;
641 if (irpsp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG))
643 irp->IoStatus.u.Status = rc = STATUS_BUFFER_OVERFLOW;
645 else
647 rc = RingBuffer_SetSize(extension->ring_buffer, *(ULONG*)irp->AssociatedIrp.SystemBuffer);
648 irp->IoStatus.u.Status = rc;
650 break;
652 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS:
654 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
656 irp->IoStatus.u.Status = rc = STATUS_BUFFER_TOO_SMALL;
658 else
660 *(ULONG*)irp->AssociatedIrp.SystemBuffer = RingBuffer_GetSize(extension->ring_buffer);
661 rc = irp->IoStatus.u.Status = STATUS_SUCCESS;
663 break;
665 case IOCTL_HID_GET_FEATURE:
666 rc = HID_get_feature(device, irp);
667 break;
668 case IOCTL_HID_SET_FEATURE:
669 case IOCTL_HID_SET_OUTPUT_REPORT:
670 rc = HID_set_to_device(device, irp);
671 break;
672 default:
674 ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;
675 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
676 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
677 irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
678 rc = STATUS_UNSUCCESSFUL;
679 break;
683 if (rc != STATUS_PENDING)
684 IoCompleteRequest( irp, IO_NO_INCREMENT );
686 return rc;
689 NTSTATUS WINAPI HID_Device_read(DEVICE_OBJECT *device, IRP *irp)
691 HID_XFER_PACKET *packet;
692 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
693 UINT buffer_size = RingBuffer_GetBufferSize(ext->ring_buffer);
694 NTSTATUS rc = STATUS_SUCCESS;
695 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
696 int ptr = -1;
698 packet = HeapAlloc(GetProcessHeap(), 0, buffer_size);
699 ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
701 irp->IoStatus.Information = 0;
702 RingBuffer_ReadNew(ext->ring_buffer, ptr, packet, &buffer_size);
704 if (buffer_size)
706 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
707 NTSTATUS rc;
708 ULONG out_length;
709 packet->reportBuffer = (BYTE *)packet + sizeof(*packet);
710 TRACE_(hid_report)("Got Packet %p %i\n", packet->reportBuffer, packet->reportBufferLen);
712 rc = copy_packet_into_buffer(packet, irp->AssociatedIrp.SystemBuffer, irpsp->Parameters.Read.Length, &out_length);
713 irp->IoStatus.Information = out_length;
714 irp->IoStatus.u.Status = rc;
715 IoCompleteRequest(irp, IO_NO_INCREMENT);
717 else
719 BASE_DEVICE_EXTENSION *extension = device->DeviceExtension;
720 if (extension->poll_interval)
722 KIRQL old_irql;
723 TRACE_(hid_report)("Queue irp\n");
725 KeAcquireSpinLock(&ext->irp_queue_lock, &old_irql);
727 IoSetCancelRoutine(irp, read_cancel_routine);
728 if (irp->Cancel && !IoSetCancelRoutine(irp, NULL))
730 /* IRP was canceled before we set cancel routine */
731 InitializeListHead(&irp->Tail.Overlay.s.ListEntry);
732 KeReleaseSpinLock(&ext->irp_queue_lock, old_irql);
733 return STATUS_CANCELLED;
736 InsertTailList(&ext->irp_queue, &irp->Tail.Overlay.s.ListEntry);
737 IoMarkIrpPending(irp);
739 KeReleaseSpinLock(&ext->irp_queue_lock, old_irql);
740 rc = STATUS_PENDING;
742 else
744 HID_XFER_PACKET packet;
745 TRACE("No packet, but opportunistic reads enabled\n");
746 packet.reportId = ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0];
747 packet.reportBuffer = &((BYTE*)irp->AssociatedIrp.SystemBuffer)[1];
748 packet.reportBufferLen = irpsp->Parameters.Read.Length - 1;
749 rc = call_minidriver(IOCTL_HID_GET_INPUT_REPORT, device, NULL, 0, &packet, sizeof(packet));
751 if (rc == STATUS_SUCCESS)
753 ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0] = packet.reportId;
754 irp->IoStatus.Information = packet.reportBufferLen + 1;
755 irp->IoStatus.u.Status = rc;
757 IoCompleteRequest(irp, IO_NO_INCREMENT);
760 HeapFree(GetProcessHeap(), 0, packet);
762 return rc;
765 NTSTATUS WINAPI HID_Device_write(DEVICE_OBJECT *device, IRP *irp)
767 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
768 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
769 HID_XFER_PACKET packet;
770 ULONG max_len;
771 NTSTATUS rc;
773 irp->IoStatus.Information = 0;
775 TRACE_(hid_report)("Device %p Buffer length %i Buffer %p\n", device, irpsp->Parameters.Write.Length, irp->AssociatedIrp.SystemBuffer);
776 packet.reportId = ((BYTE*)irp->AssociatedIrp.SystemBuffer)[0];
777 if (packet.reportId == 0)
779 packet.reportBuffer = &((BYTE*)irp->AssociatedIrp.SystemBuffer)[1];
780 packet.reportBufferLen = irpsp->Parameters.Write.Length - 1;
781 max_len = ext->preparseData->caps.OutputReportByteLength;
783 else
785 packet.reportBuffer = irp->AssociatedIrp.SystemBuffer;
786 packet.reportBufferLen = irpsp->Parameters.Write.Length;
787 max_len = (ext->preparseData->reports[ext->preparseData->reportIdx[HidP_Output][packet.reportId]].bitSize + 7) / 8;
789 if (packet.reportBufferLen > max_len)
790 packet.reportBufferLen = max_len;
792 TRACE_(hid_report)("(id %i, len %i buffer %p)\n", packet.reportId, packet.reportBufferLen, packet.reportBuffer);
794 rc = call_minidriver(IOCTL_HID_WRITE_REPORT, device, NULL, 0, &packet, sizeof(packet));
796 irp->IoStatus.u.Status = rc;
797 if (irp->IoStatus.u.Status == STATUS_SUCCESS)
798 irp->IoStatus.Information = irpsp->Parameters.Write.Length;
799 else
800 irp->IoStatus.Information = 0;
802 TRACE_(hid_report)("Result 0x%x wrote %li bytes\n", rc, irp->IoStatus.Information);
804 IoCompleteRequest( irp, IO_NO_INCREMENT );
805 return rc;
808 NTSTATUS WINAPI HID_Device_create(DEVICE_OBJECT *device, IRP *irp)
810 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
812 TRACE("Open handle on device %p\n", device);
813 irp->Tail.Overlay.OriginalFileObject->FsContext = UlongToPtr(RingBuffer_AddPointer(ext->ring_buffer));
814 irp->IoStatus.u.Status = STATUS_SUCCESS;
815 IoCompleteRequest( irp, IO_NO_INCREMENT );
816 return STATUS_SUCCESS;
819 NTSTATUS WINAPI HID_Device_close(DEVICE_OBJECT *device, IRP *irp)
821 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
822 int ptr = PtrToUlong(irp->Tail.Overlay.OriginalFileObject->FsContext);
823 TRACE("Close handle on device %p\n", device);
824 RingBuffer_RemovePointer(ext->ring_buffer, ptr);
825 irp->IoStatus.u.Status = STATUS_SUCCESS;
826 IoCompleteRequest( irp, IO_NO_INCREMENT );
827 return STATUS_SUCCESS;