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
27 #include "wine/debug.h"
28 #include "ddk/hidsdi.h"
29 #include "ddk/hidtypes.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
33 WINE_DECLARE_DEBUG_CHANNEL(hid_report
);
35 IRP
*pop_irp_from_queue(BASE_DEVICE_EXTENSION
*ext
)
41 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
43 while (!irp
&& (entry
= RemoveHeadList(&ext
->u
.pdo
.irp_queue
)) != &ext
->u
.pdo
.irp_queue
)
45 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.ListEntry
);
46 if (!IoSetCancelRoutine(irp
, NULL
))
48 /* cancel routine is already cleared, meaning that it was called. let it handle completion. */
49 InitializeListHead(&irp
->Tail
.Overlay
.ListEntry
);
54 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
58 static void WINAPI
read_cancel_routine(DEVICE_OBJECT
*device
, IRP
*irp
)
60 BASE_DEVICE_EXTENSION
*ext
;
63 TRACE("cancel %p IRP on device %p\n", irp
, device
);
65 ext
= device
->DeviceExtension
;
67 IoReleaseCancelSpinLock(irp
->CancelIrql
);
69 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
71 RemoveEntryList(&irp
->Tail
.Overlay
.ListEntry
);
73 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
75 irp
->IoStatus
.Status
= STATUS_CANCELLED
;
76 irp
->IoStatus
.Information
= 0;
77 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
80 static NTSTATUS
copy_packet_into_buffer(HID_XFER_PACKET
*packet
, BYTE
* buffer
, ULONG buffer_length
, ULONG
*out_length
)
82 BOOL zero_id
= (packet
->reportId
== 0);
86 if ((zero_id
&& buffer_length
> packet
->reportBufferLen
) ||
87 (!zero_id
&& buffer_length
>= packet
->reportBufferLen
))
89 if (packet
->reportId
!= 0)
91 memcpy(buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
92 *out_length
= packet
->reportBufferLen
;
97 memcpy(&buffer
[1], packet
->reportBuffer
, packet
->reportBufferLen
);
98 *out_length
= packet
->reportBufferLen
+ 1;
100 return STATUS_SUCCESS
;
103 return STATUS_BUFFER_OVERFLOW
;
106 static void hid_device_send_input(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
)
108 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
114 data_size
= offsetof(RAWINPUT
, data
.hid
.bRawData
) + packet
->reportBufferLen
;
115 if (!(id
= ext
->u
.pdo
.preparsed_data
->reports
[0].reportID
)) data_size
+= 1;
117 if (!(rawinput
= malloc(data_size
)))
119 ERR("Failed to allocate rawinput data!\n");
123 rawinput
->header
.dwType
= RIM_TYPEHID
;
124 rawinput
->header
.dwSize
= data_size
;
125 rawinput
->header
.hDevice
= ULongToHandle(ext
->u
.pdo
.rawinput_handle
);
126 rawinput
->header
.wParam
= RIM_INPUT
;
127 rawinput
->data
.hid
.dwCount
= 1;
128 rawinput
->data
.hid
.dwSizeHid
= data_size
- offsetof(RAWINPUT
, data
.hid
.bRawData
);
130 report
= rawinput
->data
.hid
.bRawData
;
131 if (!id
) *report
++ = 0;
132 memcpy(report
, packet
->reportBuffer
, packet
->reportBufferLen
);
134 input
.type
= INPUT_HARDWARE
;
135 input
.hi
.uMsg
= WM_INPUT
;
136 input
.hi
.wParamH
= 0;
137 input
.hi
.wParamL
= 0;
138 __wine_send_input(0, &input
, rawinput
);
143 static void HID_Device_processQueue(DEVICE_OBJECT
*device
)
146 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
147 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->u
.pdo
.ring_buffer
);
148 HID_XFER_PACKET
*packet
;
150 packet
= malloc(buffer_size
);
152 while((irp
= pop_irp_from_queue(ext
)))
155 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
157 RingBuffer_Read(ext
->u
.pdo
.ring_buffer
, ptr
, packet
, &buffer_size
);
162 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
163 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
164 TRACE_(hid_report
)("Processing Request (%i)\n",ptr
);
165 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
166 irp
->IoStatus
.Status
= rc
;
167 irp
->IoStatus
.Information
= out_length
;
171 irp
->IoStatus
.Information
= 0;
172 irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
174 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
179 static DWORD CALLBACK
hid_device_thread(void *args
)
181 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
184 IO_STATUS_BLOCK irp_status
;
185 HID_XFER_PACKET
*packet
;
188 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
189 USHORT report_size
= ext
->u
.pdo
.preparsed_data
->caps
.InputReportByteLength
;
191 packet
= malloc(sizeof(*packet
) + report_size
);
192 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
194 if (ext
->u
.pdo
.information
.Polled
)
200 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
202 packet
->reportBufferLen
= report_size
;
203 packet
->reportId
= 0;
205 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_GET_INPUT_REPORT
, ext
->u
.pdo
.parent_fdo
,
206 NULL
, 0, packet
, sizeof(*packet
), TRUE
, &event
, &irp_status
);
208 if (IoCallDriver(ext
->u
.pdo
.parent_fdo
, irp
) == STATUS_PENDING
)
209 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
211 if (irp_status
.Status
== STATUS_SUCCESS
)
213 RingBuffer_Write(ext
->u
.pdo
.ring_buffer
, packet
);
214 hid_device_send_input(device
, packet
);
215 HID_Device_processQueue(device
);
218 rc
= WaitForSingleObject(ext
->u
.pdo
.halt_event
,
219 ext
->u
.pdo
.poll_interval
? ext
->u
.pdo
.poll_interval
: DEFAULT_POLL_INTERVAL
);
221 if (rc
== WAIT_OBJECT_0
)
223 else if (rc
!= WAIT_TIMEOUT
)
224 ERR("Wait returned unexpected value %x\n",rc
);
229 INT exit_now
= FALSE
;
235 KeInitializeEvent(&event
, NotificationEvent
, FALSE
);
237 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT
, ext
->u
.pdo
.parent_fdo
,
238 NULL
, 0, packet
->reportBuffer
, report_size
, TRUE
, &event
, &irp_status
);
240 if (IoCallDriver(ext
->u
.pdo
.parent_fdo
, irp
) == STATUS_PENDING
)
241 KeWaitForSingleObject(&event
, Executive
, KernelMode
, FALSE
, NULL
);
243 rc
= WaitForSingleObject(ext
->u
.pdo
.halt_event
, 0);
244 if (rc
== WAIT_OBJECT_0
)
247 if (!exit_now
&& irp_status
.Status
== STATUS_SUCCESS
)
249 packet
->reportBufferLen
= irp_status
.Information
;
250 if (ext
->u
.pdo
.preparsed_data
->reports
[0].reportID
)
251 packet
->reportId
= packet
->reportBuffer
[0];
253 packet
->reportId
= 0;
254 RingBuffer_Write(ext
->u
.pdo
.ring_buffer
, packet
);
255 hid_device_send_input(device
, packet
);
256 HID_Device_processQueue(device
);
264 TRACE("Device thread exiting\n");
268 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
270 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
271 ext
->u
.pdo
.halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
272 ext
->u
.pdo
.thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
275 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP
*irp
, BASE_DEVICE_EXTENSION
*ext
)
277 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
278 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
280 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
281 irp
->IoStatus
.Information
= 0;
285 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &ext
->u
.pdo
.information
, sizeof(HID_COLLECTION_INFORMATION
));
286 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
287 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
289 return STATUS_SUCCESS
;
292 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(IRP
*irp
, BASE_DEVICE_EXTENSION
*ext
)
294 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
295 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
297 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< data
->dwSize
)
299 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
300 irp
->IoStatus
.Information
= 0;
304 memcpy(irp
->UserBuffer
, data
, data
->dwSize
);
305 irp
->IoStatus
.Information
= data
->dwSize
;
306 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
308 return STATUS_SUCCESS
;
311 static NTSTATUS
handle_minidriver_string(BASE_DEVICE_EXTENSION
*ext
, IRP
*irp
, SHORT index
)
313 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
318 InputBuffer
= MAKELONG(index
, 0);
319 status
= call_minidriver(IOCTL_HID_GET_STRING
, ext
->u
.pdo
.parent_fdo
,
320 ULongToPtr(InputBuffer
), sizeof(InputBuffer
), buffer
, sizeof(buffer
));
322 if (status
== STATUS_SUCCESS
)
324 WCHAR
*out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
325 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
326 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
327 lstrcpynW(out_buffer
, buffer
, length
);
328 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
330 irp
->IoStatus
.Status
= status
;
332 return STATUS_SUCCESS
;
335 static NTSTATUS
HID_get_feature(BASE_DEVICE_EXTENSION
*ext
, IRP
*irp
)
337 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
338 HID_XFER_PACKET
*packet
;
340 NTSTATUS rc
= STATUS_SUCCESS
;
343 irp
->IoStatus
.Information
= 0;
345 out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
346 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", ext
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, out_buffer
);
348 if (!irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
|| !out_buffer
)
350 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
354 len
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
355 packet
= malloc(len
);
356 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
357 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
358 packet
->reportId
= out_buffer
[0];
360 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
->reportId
, packet
->reportBufferLen
, packet
->reportBuffer
);
362 rc
= call_minidriver(IOCTL_HID_GET_FEATURE
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, packet
, sizeof(*packet
));
364 irp
->IoStatus
.Status
= rc
;
365 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
367 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
368 memcpy(out_buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
371 irp
->IoStatus
.Information
= 0;
373 TRACE_(hid_report
)("Result 0x%x get %li bytes\n", rc
, irp
->IoStatus
.Information
);
380 static NTSTATUS
HID_set_to_device(DEVICE_OBJECT
*device
, IRP
*irp
)
382 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
383 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
384 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
385 HID_XFER_PACKET packet
;
389 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
, irp
->AssociatedIrp
.SystemBuffer
);
390 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
391 if (packet
.reportId
== 0)
393 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
394 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
- 1;
395 if (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_HID_SET_FEATURE
)
396 max_len
= data
->caps
.FeatureReportByteLength
;
398 max_len
= data
->caps
.OutputReportByteLength
;
402 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
403 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
404 if (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_HID_SET_FEATURE
)
405 max_len
= data
->reports
[data
->reportIdx
[HidP_Feature
][packet
.reportId
]].bitSize
;
407 max_len
= data
->reports
[data
->reportIdx
[HidP_Output
][packet
.reportId
]].bitSize
;
408 max_len
= (max_len
+ 7) / 8;
410 if (packet
.reportBufferLen
> max_len
)
411 packet
.reportBufferLen
= max_len
;
413 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
415 rc
= call_minidriver(irpsp
->Parameters
.DeviceIoControl
.IoControlCode
,
416 ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
));
418 irp
->IoStatus
.Status
= rc
;
419 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
420 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
422 irp
->IoStatus
.Information
= 0;
424 TRACE_(hid_report
)("Result 0x%x set %li bytes\n", rc
, irp
->IoStatus
.Information
);
429 NTSTATUS WINAPI
pdo_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
431 NTSTATUS rc
= STATUS_SUCCESS
;
432 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
433 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
437 irp
->IoStatus
.Information
= 0;
439 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
441 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
442 removed
= ext
->u
.pdo
.removed
;
443 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
447 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
448 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
449 return STATUS_DELETE_PENDING
;
452 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
454 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
455 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
456 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
458 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
459 irp
->IoStatus
.Information
= 0;
462 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.poll_interval
;
463 irp
->IoStatus
.Information
= sizeof(ULONG
);
464 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
466 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
469 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
470 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
472 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
475 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
476 if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
478 ext
->u
.pdo
.poll_interval
= poll_interval
;
479 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
482 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
485 case IOCTL_HID_GET_PRODUCT_STRING
:
487 rc
= handle_minidriver_string(ext
, irp
, HID_STRING_ID_IPRODUCT
);
490 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
492 rc
= handle_minidriver_string(ext
, irp
, HID_STRING_ID_ISERIALNUMBER
);
495 case IOCTL_HID_GET_MANUFACTURER_STRING
:
497 rc
= handle_minidriver_string(ext
, irp
, HID_STRING_ID_IMANUFACTURER
);
500 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
502 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, ext
);
505 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
507 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, ext
);
510 case IOCTL_HID_GET_INPUT_REPORT
:
512 HID_XFER_PACKET
*packet
;
513 UINT packet_size
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
514 BYTE
*buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
517 if (!irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
|| !buffer
)
519 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
523 packet
= malloc(packet_size
);
525 if (ext
->u
.pdo
.preparsed_data
->reports
[0].reportID
)
526 packet
->reportId
= buffer
[0];
528 packet
->reportId
= 0;
529 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
530 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
- 1;
532 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, packet
, sizeof(*packet
));
533 if (rc
== STATUS_SUCCESS
)
535 rc
= copy_packet_into_buffer(packet
, buffer
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, &out_length
);
536 irp
->IoStatus
.Information
= out_length
;
539 irp
->IoStatus
.Information
= 0;
540 irp
->IoStatus
.Status
= rc
;
544 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
546 irp
->IoStatus
.Information
= 0;
548 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
550 irp
->IoStatus
.Status
= rc
= STATUS_BUFFER_OVERFLOW
;
554 rc
= RingBuffer_SetSize(ext
->u
.pdo
.ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
555 irp
->IoStatus
.Status
= rc
;
559 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
561 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
563 irp
->IoStatus
.Information
= 0;
564 irp
->IoStatus
.Status
= rc
= STATUS_BUFFER_TOO_SMALL
;
568 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(ext
->u
.pdo
.ring_buffer
);
569 irp
->IoStatus
.Information
= sizeof(ULONG
);
570 rc
= irp
->IoStatus
.Status
= STATUS_SUCCESS
;
574 case IOCTL_HID_GET_FEATURE
:
575 rc
= HID_get_feature(ext
, irp
);
577 case IOCTL_HID_SET_FEATURE
:
578 case IOCTL_HID_SET_OUTPUT_REPORT
:
579 rc
= HID_set_to_device(device
, irp
);
583 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
584 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
585 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
586 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
587 rc
= STATUS_UNSUCCESSFUL
;
592 if (rc
!= STATUS_PENDING
)
593 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
598 NTSTATUS WINAPI
pdo_read(DEVICE_OBJECT
*device
, IRP
*irp
)
600 HID_XFER_PACKET
*packet
;
601 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
602 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
603 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->u
.pdo
.ring_buffer
);
604 NTSTATUS rc
= STATUS_SUCCESS
;
605 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
610 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
611 removed
= ext
->u
.pdo
.removed
;
612 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
616 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
617 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
618 return STATUS_DELETE_PENDING
;
621 if (irpsp
->Parameters
.Read
.Length
< data
->caps
.InputReportByteLength
)
623 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
624 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
625 return STATUS_INVALID_BUFFER_SIZE
;
628 packet
= malloc(buffer_size
);
629 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
631 irp
->IoStatus
.Information
= 0;
632 RingBuffer_ReadNew(ext
->u
.pdo
.ring_buffer
, ptr
, packet
, &buffer_size
);
636 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
639 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
640 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
642 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
643 irp
->IoStatus
.Information
= out_length
;
644 irp
->IoStatus
.Status
= rc
;
645 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
649 if (ext
->u
.pdo
.poll_interval
)
652 TRACE_(hid_report
)("Queue irp\n");
654 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
656 IoSetCancelRoutine(irp
, read_cancel_routine
);
657 if (irp
->Cancel
&& !IoSetCancelRoutine(irp
, NULL
))
659 /* IRP was canceled before we set cancel routine */
660 InitializeListHead(&irp
->Tail
.Overlay
.ListEntry
);
661 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
662 return STATUS_CANCELLED
;
665 InsertTailList(&ext
->u
.pdo
.irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
666 IoMarkIrpPending(irp
);
668 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
673 HID_XFER_PACKET packet
;
674 TRACE("No packet, but opportunistic reads enabled\n");
675 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
676 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
677 packet
.reportBufferLen
= irpsp
->Parameters
.Read
.Length
- 1;
678 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
));
680 if (rc
== STATUS_SUCCESS
)
682 ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0] = packet
.reportId
;
683 irp
->IoStatus
.Information
= packet
.reportBufferLen
+ 1;
684 irp
->IoStatus
.Status
= rc
;
686 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
694 NTSTATUS WINAPI
pdo_write(DEVICE_OBJECT
*device
, IRP
*irp
)
696 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
697 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
698 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
699 HID_XFER_PACKET packet
;
705 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
706 removed
= ext
->u
.pdo
.removed
;
707 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
711 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
712 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
713 return STATUS_DELETE_PENDING
;
716 if (!irpsp
->Parameters
.Write
.Length
)
718 irp
->IoStatus
.Status
= STATUS_INVALID_USER_BUFFER
;
719 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
720 return irp
->IoStatus
.Status
;
723 if (irpsp
->Parameters
.Write
.Length
< data
->caps
.OutputReportByteLength
)
725 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
726 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
727 return irp
->IoStatus
.Status
;
730 irp
->IoStatus
.Information
= 0;
732 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
733 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
734 if (packet
.reportId
== 0)
736 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
737 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
- 1;
738 max_len
= data
->caps
.OutputReportByteLength
;
742 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
743 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
744 max_len
= (data
->reports
[data
->reportIdx
[HidP_Output
][packet
.reportId
]].bitSize
+ 7) / 8;
746 if (packet
.reportBufferLen
> max_len
)
747 packet
.reportBufferLen
= max_len
;
749 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
751 rc
= call_minidriver(IOCTL_HID_WRITE_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
));
753 irp
->IoStatus
.Status
= rc
;
754 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
755 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
757 irp
->IoStatus
.Information
= 0;
759 TRACE_(hid_report
)("Result 0x%x wrote %li bytes\n", rc
, irp
->IoStatus
.Information
);
761 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
765 NTSTATUS WINAPI
pdo_create(DEVICE_OBJECT
*device
, IRP
*irp
)
767 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
769 TRACE("Open handle on device %p\n", device
);
770 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->u
.pdo
.ring_buffer
));
771 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
772 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
773 return STATUS_SUCCESS
;
776 NTSTATUS WINAPI
pdo_close(DEVICE_OBJECT
*device
, IRP
*irp
)
778 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
779 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
780 TRACE("Close handle on device %p\n", device
);
781 RingBuffer_RemovePointer(ext
->u
.pdo
.ring_buffer
, ptr
);
782 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
783 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
784 return STATUS_SUCCESS
;