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 NTSTATUS
HID_CreateDevice(DEVICE_OBJECT
*native_device
, HID_MINIDRIVER_REGISTRATION
*driver
, DEVICE_OBJECT
**device
)
46 BASE_DEVICE_EXTENSION
*ext
;
48 swprintf(dev_name
, ARRAY_SIZE(dev_name
), L
"\\Device\\HID#%p&%p", driver
->DriverObject
, native_device
);
49 RtlInitUnicodeString( &nameW
, dev_name
);
51 TRACE("Create base hid device %s\n", debugstr_w(dev_name
));
53 status
= IoCreateDevice(driver
->DriverObject
, driver
->DeviceExtensionSize
+ sizeof(BASE_DEVICE_EXTENSION
), &nameW
, 0, 0, FALSE
, device
);
56 FIXME( "failed to create device error %x\n", status
);
60 ext
= (*device
)->DeviceExtension
;
62 ext
->deviceExtension
.MiniDeviceExtension
= ext
+ 1;
63 ext
->deviceExtension
.PhysicalDeviceObject
= *device
;
64 ext
->deviceExtension
.NextDeviceObject
= native_device
;
65 ext
->device_name
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(dev_name
) + 1) * sizeof(WCHAR
));
66 lstrcpyW(ext
->device_name
, dev_name
);
67 ext
->link_name
.Buffer
= NULL
;
69 IoAttachDeviceToDeviceStack(*device
, native_device
);
71 return STATUS_SUCCESS
;
74 NTSTATUS
HID_LinkDevice(DEVICE_OBJECT
*device
)
76 WCHAR device_instance_id
[MAX_DEVICE_ID_LEN
];
82 BASE_DEVICE_EXTENSION
*ext
;
84 HidD_GetHidGuid(&hidGuid
);
85 ext
= device
->DeviceExtension
;
87 RtlInitUnicodeString( &nameW
, ext
->device_name
);
89 lstrcpyW(device_instance_id
, ext
->device_id
);
90 lstrcatW(device_instance_id
, L
"\\");
91 lstrcatW(device_instance_id
, ext
->instance_id
);
93 devinfo
= SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_HIDCLASS
, NULL
);
94 if (devinfo
== INVALID_HANDLE_VALUE
)
96 FIXME( "failed to get ClassDevs %x\n", GetLastError());
97 return STATUS_UNSUCCESSFUL
;
99 Data
.cbSize
= sizeof(Data
);
100 if (SetupDiCreateDeviceInfoW(devinfo
, device_instance_id
, &GUID_DEVCLASS_HIDCLASS
, NULL
, NULL
, DICD_INHERIT_CLASSDRVS
, &Data
))
102 if (!SetupDiRegisterDeviceInfo(devinfo
, &Data
, 0, NULL
, NULL
, NULL
))
104 FIXME( "failed to register device info %x\n", GetLastError());
108 else if (GetLastError() != ERROR_DEVINST_ALREADY_EXISTS
)
110 FIXME( "failed to create device info %x\n", GetLastError());
113 SetupDiDestroyDeviceInfoList(devinfo
);
115 status
= IoRegisterDeviceInterface(device
, &hidGuid
, NULL
, &ext
->link_name
);
116 if (status
!= STATUS_SUCCESS
)
118 FIXME( "failed to register device interface %x\n", status
);
122 /* FIXME: This should probably be done in mouhid.sys. */
123 if (ext
->preparseData
->caps
.UsagePage
== HID_USAGE_PAGE_GENERIC
124 && ext
->preparseData
->caps
.Usage
== HID_USAGE_GENERIC_MOUSE
)
126 if (!IoRegisterDeviceInterface(device
, &GUID_DEVINTERFACE_MOUSE
, NULL
, &ext
->mouse_link_name
))
127 ext
->is_mouse
= TRUE
;
130 return STATUS_SUCCESS
;
133 SetupDiDestroyDeviceInfoList(devinfo
);
134 return STATUS_UNSUCCESSFUL
;
137 static IRP
*pop_irp_from_queue(BASE_DEVICE_EXTENSION
*ext
)
143 KeAcquireSpinLock(&ext
->irp_queue_lock
, &old_irql
);
145 while (!irp
&& (entry
= RemoveHeadList(&ext
->irp_queue
)) != &ext
->irp_queue
)
147 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
148 if (!IoSetCancelRoutine(irp
, NULL
))
150 /* cancel routine is already cleared, meaning that it was called. let it handle completion. */
151 InitializeListHead(&irp
->Tail
.Overlay
.s
.ListEntry
);
156 KeReleaseSpinLock(&ext
->irp_queue_lock
, old_irql
);
160 static void WINAPI
read_cancel_routine(DEVICE_OBJECT
*device
, IRP
*irp
)
162 BASE_DEVICE_EXTENSION
*ext
;
165 TRACE("cancel %p IRP on device %p\n", irp
, device
);
167 ext
= device
->DeviceExtension
;
169 IoReleaseCancelSpinLock(irp
->CancelIrql
);
171 KeAcquireSpinLock(&ext
->irp_queue_lock
, &old_irql
);
173 RemoveEntryList(&irp
->Tail
.Overlay
.s
.ListEntry
);
175 KeReleaseSpinLock(&ext
->irp_queue_lock
, old_irql
);
177 irp
->IoStatus
.u
.Status
= STATUS_CANCELLED
;
178 irp
->IoStatus
.Information
= 0;
179 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
182 void HID_DeleteDevice(DEVICE_OBJECT
*device
)
184 BASE_DEVICE_EXTENSION
*ext
;
187 ext
= device
->DeviceExtension
;
191 SetEvent(ext
->halt_event
);
192 WaitForSingleObject(ext
->thread
, INFINITE
);
194 CloseHandle(ext
->halt_event
);
196 HeapFree(GetProcessHeap(), 0, ext
->preparseData
);
197 if (ext
->ring_buffer
)
198 RingBuffer_Destroy(ext
->ring_buffer
);
200 while((irp
= pop_irp_from_queue(ext
)))
202 irp
->IoStatus
.u
.Status
= STATUS_DEVICE_REMOVED
;
203 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
206 TRACE("Delete device(%p) %s\n", device
, debugstr_w(ext
->device_name
));
207 HeapFree(GetProcessHeap(), 0, ext
->device_name
);
208 RtlFreeUnicodeString(&ext
->link_name
);
210 IoDetachDevice(ext
->deviceExtension
.NextDeviceObject
);
211 IoDeleteDevice(device
);
214 static NTSTATUS
copy_packet_into_buffer(HID_XFER_PACKET
*packet
, BYTE
* buffer
, ULONG buffer_length
, ULONG
*out_length
)
216 BOOL zero_id
= (packet
->reportId
== 0);
220 if ((zero_id
&& buffer_length
> packet
->reportBufferLen
) ||
221 (!zero_id
&& buffer_length
>= packet
->reportBufferLen
))
223 if (packet
->reportId
!= 0)
225 memcpy(buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
226 *out_length
= packet
->reportBufferLen
;
231 memcpy(&buffer
[1], packet
->reportBuffer
, packet
->reportBufferLen
);
232 *out_length
= packet
->reportBufferLen
+ 1;
234 return STATUS_SUCCESS
;
237 return STATUS_BUFFER_OVERFLOW
;
240 static void HID_Device_processQueue(DEVICE_OBJECT
*device
)
243 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
244 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
245 HID_XFER_PACKET
*packet
;
247 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
249 while((irp
= pop_irp_from_queue(ext
)))
252 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
254 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
259 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
260 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
261 TRACE_(hid_report
)("Processing Request (%i)\n",ptr
);
262 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
263 irp
->IoStatus
.u
.Status
= rc
;
264 irp
->IoStatus
.Information
= out_length
;
268 irp
->IoStatus
.Information
= 0;
269 irp
->IoStatus
.u
.Status
= STATUS_UNSUCCESSFUL
;
271 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
273 HeapFree(GetProcessHeap(), 0, packet
);
276 static NTSTATUS WINAPI
read_Completion(DEVICE_OBJECT
*deviceObject
, IRP
*irp
, void *context
)
278 HANDLE event
= context
;
280 return STATUS_MORE_PROCESSING_REQUIRED
;
283 static DWORD CALLBACK
hid_device_thread(void *args
)
285 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
288 IO_STATUS_BLOCK irp_status
;
289 HID_XFER_PACKET
*packet
;
294 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
295 events
[0] = CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
296 events
[1] = ext
->halt_event
;
298 packet
= HeapAlloc(GetProcessHeap(), 0, sizeof(*packet
) + ext
->preparseData
->caps
.InputReportByteLength
);
299 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
301 if (ext
->information
.Polled
)
305 ResetEvent(events
[0]);
307 packet
->reportBufferLen
= ext
->preparseData
->caps
.InputReportByteLength
;
308 packet
->reportId
= 0;
310 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_GET_INPUT_REPORT
,
311 device
, NULL
, 0, packet
, sizeof(*packet
), TRUE
, NULL
,
314 IoSetCompletionRoutine(irp
, read_Completion
, events
[0], TRUE
, TRUE
, TRUE
);
315 ntrc
= IoCallDriver(device
, irp
);
317 if (ntrc
== STATUS_PENDING
)
318 WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
320 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
322 RingBuffer_Write(ext
->ring_buffer
, packet
);
323 HID_Device_processQueue(device
);
326 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
328 rc
= WaitForSingleObject(ext
->halt_event
, ext
->poll_interval
? ext
->poll_interval
: DEFAULT_POLL_INTERVAL
);
330 if (rc
== WAIT_OBJECT_0
)
332 else if (rc
!= WAIT_TIMEOUT
)
333 ERR("Wait returned unexpected value %x\n",rc
);
338 INT exit_now
= FALSE
;
342 ResetEvent(events
[0]);
344 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT
,
345 device
, NULL
, 0, packet
->reportBuffer
,
346 ext
->preparseData
->caps
.InputReportByteLength
, TRUE
, NULL
,
349 IoSetCompletionRoutine(irp
, read_Completion
, events
[0], TRUE
, TRUE
, TRUE
);
350 ntrc
= IoCallDriver(device
, irp
);
352 if (ntrc
== STATUS_PENDING
)
354 WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
357 rc
= WaitForSingleObject(ext
->halt_event
, 0);
358 if (rc
== WAIT_OBJECT_0
)
361 if (!exit_now
&& irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
363 packet
->reportBufferLen
= irp
->IoStatus
.Information
;
364 if (ext
->preparseData
->reports
[0].reportID
)
365 packet
->reportId
= packet
->reportBuffer
[0];
367 packet
->reportId
= 0;
368 RingBuffer_Write(ext
->ring_buffer
, packet
);
369 HID_Device_processQueue(device
);
372 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
379 /* FIXME: releasing packet requires IRP cancellation support */
380 CloseHandle(events
[0]);
382 TRACE("Device thread exiting\n");
386 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
388 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
389 ext
->halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
390 ext
->thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
393 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
395 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
396 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
398 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
399 irp
->IoStatus
.Information
= 0;
403 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &base
->information
, sizeof(HID_COLLECTION_INFORMATION
));
404 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
405 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
407 return STATUS_SUCCESS
;
410 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
412 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
414 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< base
->preparseData
->dwSize
)
416 irp
->IoStatus
.u
.Status
= STATUS_INVALID_BUFFER_SIZE
;
417 irp
->IoStatus
.Information
= 0;
421 memcpy(irp
->UserBuffer
, base
->preparseData
, base
->preparseData
->dwSize
);
422 irp
->IoStatus
.Information
= base
->preparseData
->dwSize
;
423 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
425 return STATUS_SUCCESS
;
428 static NTSTATUS
handle_minidriver_string(DEVICE_OBJECT
*device
, IRP
*irp
, SHORT index
)
430 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
435 InputBuffer
= MAKELONG(index
, 0);
436 status
= call_minidriver(IOCTL_HID_GET_STRING
, device
, ULongToPtr(InputBuffer
), sizeof(InputBuffer
), buffer
, sizeof(buffer
));
438 if (status
== STATUS_SUCCESS
)
440 WCHAR
*out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
441 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
442 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
443 lstrcpynW(out_buffer
, buffer
, length
);
444 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
446 irp
->IoStatus
.u
.Status
= status
;
448 return STATUS_SUCCESS
;
451 static NTSTATUS
HID_get_feature(DEVICE_OBJECT
*device
, IRP
*irp
)
453 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
454 HID_XFER_PACKET
*packet
;
456 NTSTATUS rc
= STATUS_SUCCESS
;
459 irp
->IoStatus
.Information
= 0;
461 out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
462 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, out_buffer
);
464 len
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
465 packet
= HeapAlloc(GetProcessHeap(), 0, len
);
466 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
467 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
468 packet
->reportId
= out_buffer
[0];
470 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
->reportId
, packet
->reportBufferLen
, packet
->reportBuffer
);
472 rc
= call_minidriver(IOCTL_HID_GET_FEATURE
, device
, NULL
, 0, packet
, sizeof(*packet
));
474 irp
->IoStatus
.u
.Status
= rc
;
475 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
477 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
478 memcpy(out_buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
481 irp
->IoStatus
.Information
= 0;
483 TRACE_(hid_report
)("Result 0x%x get %li bytes\n", rc
, irp
->IoStatus
.Information
);
485 HeapFree(GetProcessHeap(), 0, packet
);
490 static NTSTATUS
HID_set_to_device(DEVICE_OBJECT
*device
, IRP
*irp
)
492 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
493 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
494 HID_XFER_PACKET packet
;
498 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
, irp
->AssociatedIrp
.SystemBuffer
);
499 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
500 if (packet
.reportId
== 0)
502 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
503 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
- 1;
504 if (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_HID_SET_FEATURE
)
505 max_len
= ext
->preparseData
->caps
.FeatureReportByteLength
;
507 max_len
= ext
->preparseData
->caps
.OutputReportByteLength
;
511 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
512 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
513 if (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_HID_SET_FEATURE
)
514 max_len
= (ext
->preparseData
->reports
[ext
->preparseData
->reportIdx
[HidP_Feature
][packet
.reportId
]].bitSize
+ 7) / 8;
516 max_len
= (ext
->preparseData
->reports
[ext
->preparseData
->reportIdx
[HidP_Output
][packet
.reportId
]].bitSize
+ 7) / 8;
518 if (packet
.reportBufferLen
> max_len
)
519 packet
.reportBufferLen
= max_len
;
521 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
523 rc
= call_minidriver(irpsp
->Parameters
.DeviceIoControl
.IoControlCode
,
524 device
, NULL
, 0, &packet
, sizeof(packet
));
526 irp
->IoStatus
.u
.Status
= rc
;
527 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
528 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
530 irp
->IoStatus
.Information
= 0;
532 TRACE_(hid_report
)("Result 0x%x set %li bytes\n", rc
, irp
->IoStatus
.Information
);
537 NTSTATUS WINAPI
HID_Device_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
539 NTSTATUS rc
= STATUS_SUCCESS
;
540 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
541 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
543 irp
->IoStatus
.Information
= 0;
545 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
547 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
549 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
550 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
551 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
553 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
554 irp
->IoStatus
.Information
= 0;
557 *((ULONG
*)irp
->AssociatedIrp
.SystemBuffer
) = extension
->poll_interval
;
558 irp
->IoStatus
.Information
= sizeof(ULONG
);
559 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
561 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
564 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
565 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
567 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_TOO_SMALL
;
570 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
571 if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
573 extension
->poll_interval
= poll_interval
;
574 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
577 irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
580 case IOCTL_HID_GET_PRODUCT_STRING
:
582 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IPRODUCT
);
585 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
587 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_ISERIALNUMBER
);
590 case IOCTL_HID_GET_MANUFACTURER_STRING
:
592 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IMANUFACTURER
);
595 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
597 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, extension
);
600 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
602 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, extension
);
605 case IOCTL_HID_GET_INPUT_REPORT
:
607 HID_XFER_PACKET
*packet
;
608 UINT packet_size
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
609 BYTE
*buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
612 packet
= HeapAlloc(GetProcessHeap(), 0, packet_size
);
614 if (extension
->preparseData
->reports
[0].reportID
)
615 packet
->reportId
= buffer
[0];
617 packet
->reportId
= 0;
618 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
619 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
- 1;
621 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, packet
, sizeof(*packet
));
622 if (rc
== STATUS_SUCCESS
)
624 rc
= copy_packet_into_buffer(packet
, buffer
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, &out_length
);
625 irp
->IoStatus
.Information
= out_length
;
628 irp
->IoStatus
.Information
= 0;
629 irp
->IoStatus
.u
.Status
= rc
;
630 HeapFree(GetProcessHeap(), 0, packet
);
633 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
635 irp
->IoStatus
.Information
= 0;
637 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
639 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_OVERFLOW
;
643 rc
= RingBuffer_SetSize(extension
->ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
644 irp
->IoStatus
.u
.Status
= rc
;
648 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
650 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
652 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_TOO_SMALL
;
656 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(extension
->ring_buffer
);
657 rc
= irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
661 case IOCTL_HID_GET_FEATURE
:
662 rc
= HID_get_feature(device
, irp
);
664 case IOCTL_HID_SET_FEATURE
:
665 case IOCTL_HID_SET_OUTPUT_REPORT
:
666 rc
= HID_set_to_device(device
, irp
);
670 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
671 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
672 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
673 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
674 rc
= STATUS_UNSUCCESSFUL
;
679 if (rc
!= STATUS_PENDING
)
680 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
685 NTSTATUS WINAPI
HID_Device_read(DEVICE_OBJECT
*device
, IRP
*irp
)
687 HID_XFER_PACKET
*packet
;
688 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
689 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
690 NTSTATUS rc
= STATUS_SUCCESS
;
691 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
694 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
695 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
697 irp
->IoStatus
.Information
= 0;
698 RingBuffer_ReadNew(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
702 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
705 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
706 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
708 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
709 irp
->IoStatus
.Information
= out_length
;
710 irp
->IoStatus
.u
.Status
= rc
;
711 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
715 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
716 if (extension
->poll_interval
)
719 TRACE_(hid_report
)("Queue irp\n");
721 KeAcquireSpinLock(&ext
->irp_queue_lock
, &old_irql
);
723 IoSetCancelRoutine(irp
, read_cancel_routine
);
724 if (irp
->Cancel
&& !IoSetCancelRoutine(irp
, NULL
))
726 /* IRP was canceled before we set cancel routine */
727 InitializeListHead(&irp
->Tail
.Overlay
.s
.ListEntry
);
728 KeReleaseSpinLock(&ext
->irp_queue_lock
, old_irql
);
729 return STATUS_CANCELLED
;
732 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.s
.ListEntry
);
733 IoMarkIrpPending(irp
);
735 KeReleaseSpinLock(&ext
->irp_queue_lock
, old_irql
);
740 HID_XFER_PACKET packet
;
741 TRACE("No packet, but opportunistic reads enabled\n");
742 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
743 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
744 packet
.reportBufferLen
= irpsp
->Parameters
.Read
.Length
- 1;
745 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
747 if (rc
== STATUS_SUCCESS
)
749 ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0] = packet
.reportId
;
750 irp
->IoStatus
.Information
= packet
.reportBufferLen
+ 1;
751 irp
->IoStatus
.u
.Status
= rc
;
753 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
756 HeapFree(GetProcessHeap(), 0, packet
);
761 NTSTATUS WINAPI
HID_Device_write(DEVICE_OBJECT
*device
, IRP
*irp
)
763 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
764 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
765 HID_XFER_PACKET packet
;
769 irp
->IoStatus
.Information
= 0;
771 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
772 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
773 if (packet
.reportId
== 0)
775 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
776 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
- 1;
777 max_len
= ext
->preparseData
->caps
.OutputReportByteLength
;
781 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
782 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
783 max_len
= (ext
->preparseData
->reports
[ext
->preparseData
->reportIdx
[HidP_Output
][packet
.reportId
]].bitSize
+ 7) / 8;
785 if (packet
.reportBufferLen
> max_len
)
786 packet
.reportBufferLen
= max_len
;
788 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
790 rc
= call_minidriver(IOCTL_HID_WRITE_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
792 irp
->IoStatus
.u
.Status
= rc
;
793 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
794 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
796 irp
->IoStatus
.Information
= 0;
798 TRACE_(hid_report
)("Result 0x%x wrote %li bytes\n", rc
, irp
->IoStatus
.Information
);
800 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
804 NTSTATUS WINAPI
HID_Device_create(DEVICE_OBJECT
*device
, IRP
*irp
)
806 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
808 TRACE("Open handle on device %p\n", device
);
809 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->ring_buffer
));
810 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
811 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
812 return STATUS_SUCCESS
;
815 NTSTATUS WINAPI
HID_Device_close(DEVICE_OBJECT
*device
, IRP
*irp
)
817 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
818 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
819 TRACE("Close handle on device %p\n", device
);
820 RingBuffer_RemovePointer(ext
->ring_buffer
, ptr
);
821 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
822 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
823 return STATUS_SUCCESS
;