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
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
29 #include "wine/debug.h"
30 #include "ddk/hidsdi.h"
31 #include "ddk/hidtypes.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
)
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
);
59 FIXME( "failed to create device error %x\n", 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
];
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());
112 else if (GetLastError() != ERROR_DEVINST_ALREADY_EXISTS
)
114 FIXME( "failed to create device info %x\n", GetLastError());
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
);
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
;
137 SetupDiDestroyDeviceInfoList(devinfo
);
138 return STATUS_UNSUCCESSFUL
;
141 static IRP
*pop_irp_from_queue(BASE_DEVICE_EXTENSION
*ext
)
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
);
160 KeReleaseSpinLock(&ext
->irp_queue_lock
, old_irql
);
164 static void WINAPI
read_cancel_routine(DEVICE_OBJECT
*device
, IRP
*irp
)
166 BASE_DEVICE_EXTENSION
*ext
;
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
;
191 ext
= device
->DeviceExtension
;
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);
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
;
235 memcpy(&buffer
[1], packet
->reportBuffer
, packet
->reportBufferLen
);
236 *out_length
= packet
->reportBufferLen
+ 1;
238 return STATUS_SUCCESS
;
241 return STATUS_BUFFER_OVERFLOW
;
244 static void HID_Device_processQueue(DEVICE_OBJECT
*device
)
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
)))
256 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
258 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
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
;
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
;
284 return STATUS_MORE_PROCESSING_REQUIRED
;
287 static DWORD CALLBACK
hid_device_thread(void *args
)
289 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
292 IO_STATUS_BLOCK irp_status
;
293 HID_XFER_PACKET
*packet
;
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
)
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
,
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
)
336 else if (rc
!= WAIT_TIMEOUT
)
337 ERR("Wait returned unexpected value %x\n",rc
);
342 INT exit_now
= FALSE
;
346 ResetEvent(events
[0]);
348 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT
,
349 device
, NULL
, 0, packet
->reportBuffer
,
350 ext
->preparseData
->caps
.InputReportByteLength
, TRUE
, NULL
,
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
)
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];
371 packet
->reportId
= 0;
372 RingBuffer_Write(ext
->ring_buffer
, packet
);
373 HID_Device_processQueue(device
);
376 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
383 /* FIXME: releasing packet requires IRP cancellation support */
384 CloseHandle(events
[0]);
386 TRACE("Device thread exiting\n");
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;
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;
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
);
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
;
460 NTSTATUS rc
= STATUS_SUCCESS
;
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
);
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
);
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
;
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
;
511 max_len
= ext
->preparseData
->caps
.OutputReportByteLength
;
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;
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
;
534 irp
->IoStatus
.Information
= 0;
536 TRACE_(hid_report
)("Result 0x%x set %li bytes\n", rc
, irp
->IoStatus
.Information
);
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;
561 *((ULONG
*)irp
->AssociatedIrp
.SystemBuffer
) = extension
->poll_interval
;
562 irp
->IoStatus
.Information
= sizeof(ULONG
);
563 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
565 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
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
;
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
;
581 irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
584 case IOCTL_HID_GET_PRODUCT_STRING
:
586 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IPRODUCT
);
589 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
591 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_ISERIALNUMBER
);
594 case IOCTL_HID_GET_MANUFACTURER_STRING
:
596 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IMANUFACTURER
);
599 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
601 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, extension
);
604 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
606 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, extension
);
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
);
616 packet
= HeapAlloc(GetProcessHeap(), 0, packet_size
);
618 if (extension
->preparseData
->reports
[0].reportID
)
619 packet
->reportId
= buffer
[0];
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
;
632 irp
->IoStatus
.Information
= 0;
633 irp
->IoStatus
.u
.Status
= rc
;
634 HeapFree(GetProcessHeap(), 0, packet
);
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
;
647 rc
= RingBuffer_SetSize(extension
->ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
648 irp
->IoStatus
.u
.Status
= rc
;
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
;
660 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(extension
->ring_buffer
);
661 rc
= irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
665 case IOCTL_HID_GET_FEATURE
:
666 rc
= HID_get_feature(device
, irp
);
668 case IOCTL_HID_SET_FEATURE
:
669 case IOCTL_HID_SET_OUTPUT_REPORT
:
670 rc
= HID_set_to_device(device
, irp
);
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
;
683 if (rc
!= STATUS_PENDING
)
684 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
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
);
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
);
706 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
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
);
719 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
720 if (extension
->poll_interval
)
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
);
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
);
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
;
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
;
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
;
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
);
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
;