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
.Status
= rc
= STATUS_BUFFER_TOO_SMALL
;
567 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(ext
->u
.pdo
.ring_buffer
);
568 rc
= irp
->IoStatus
.Status
= STATUS_SUCCESS
;
572 case IOCTL_HID_GET_FEATURE
:
573 rc
= HID_get_feature(ext
, irp
);
575 case IOCTL_HID_SET_FEATURE
:
576 case IOCTL_HID_SET_OUTPUT_REPORT
:
577 rc
= HID_set_to_device(device
, irp
);
581 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
582 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
583 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
584 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
585 rc
= STATUS_UNSUCCESSFUL
;
590 if (rc
!= STATUS_PENDING
)
591 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
596 NTSTATUS WINAPI
pdo_read(DEVICE_OBJECT
*device
, IRP
*irp
)
598 HID_XFER_PACKET
*packet
;
599 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
600 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->u
.pdo
.ring_buffer
);
601 NTSTATUS rc
= STATUS_SUCCESS
;
602 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
607 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
608 removed
= ext
->u
.pdo
.removed
;
609 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
613 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
614 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
615 return STATUS_DELETE_PENDING
;
618 packet
= malloc(buffer_size
);
619 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
621 irp
->IoStatus
.Information
= 0;
622 RingBuffer_ReadNew(ext
->u
.pdo
.ring_buffer
, ptr
, packet
, &buffer_size
);
626 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
629 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
630 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
632 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
633 irp
->IoStatus
.Information
= out_length
;
634 irp
->IoStatus
.Status
= rc
;
635 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
639 if (ext
->u
.pdo
.poll_interval
)
642 TRACE_(hid_report
)("Queue irp\n");
644 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
646 IoSetCancelRoutine(irp
, read_cancel_routine
);
647 if (irp
->Cancel
&& !IoSetCancelRoutine(irp
, NULL
))
649 /* IRP was canceled before we set cancel routine */
650 InitializeListHead(&irp
->Tail
.Overlay
.ListEntry
);
651 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
652 return STATUS_CANCELLED
;
655 InsertTailList(&ext
->u
.pdo
.irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
656 IoMarkIrpPending(irp
);
658 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
663 HID_XFER_PACKET packet
;
664 TRACE("No packet, but opportunistic reads enabled\n");
665 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
666 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
667 packet
.reportBufferLen
= irpsp
->Parameters
.Read
.Length
- 1;
668 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
));
670 if (rc
== STATUS_SUCCESS
)
672 ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0] = packet
.reportId
;
673 irp
->IoStatus
.Information
= packet
.reportBufferLen
+ 1;
674 irp
->IoStatus
.Status
= rc
;
676 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
684 NTSTATUS WINAPI
pdo_write(DEVICE_OBJECT
*device
, IRP
*irp
)
686 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
687 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
688 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
689 HID_XFER_PACKET packet
;
695 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
696 removed
= ext
->u
.pdo
.removed
;
697 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
701 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
702 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
703 return STATUS_DELETE_PENDING
;
706 if (!irpsp
->Parameters
.Write
.Length
)
708 irp
->IoStatus
.Status
= STATUS_INVALID_USER_BUFFER
;
709 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
710 return irp
->IoStatus
.Status
;
713 if (irpsp
->Parameters
.Write
.Length
< data
->caps
.OutputReportByteLength
)
715 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
716 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
717 return irp
->IoStatus
.Status
;
720 irp
->IoStatus
.Information
= 0;
722 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
723 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
724 if (packet
.reportId
== 0)
726 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
727 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
- 1;
728 max_len
= data
->caps
.OutputReportByteLength
;
732 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
733 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
734 max_len
= (data
->reports
[data
->reportIdx
[HidP_Output
][packet
.reportId
]].bitSize
+ 7) / 8;
736 if (packet
.reportBufferLen
> max_len
)
737 packet
.reportBufferLen
= max_len
;
739 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
741 rc
= call_minidriver(IOCTL_HID_WRITE_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
));
743 irp
->IoStatus
.Status
= rc
;
744 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
745 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
747 irp
->IoStatus
.Information
= 0;
749 TRACE_(hid_report
)("Result 0x%x wrote %li bytes\n", rc
, irp
->IoStatus
.Information
);
751 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
755 NTSTATUS WINAPI
pdo_create(DEVICE_OBJECT
*device
, IRP
*irp
)
757 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
759 TRACE("Open handle on device %p\n", device
);
760 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->u
.pdo
.ring_buffer
));
761 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
762 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
763 return STATUS_SUCCESS
;
766 NTSTATUS WINAPI
pdo_close(DEVICE_OBJECT
*device
, IRP
*irp
)
768 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
769 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
770 TRACE("Close handle on device %p\n", device
);
771 RingBuffer_RemovePointer(ext
->u
.pdo
.ring_buffer
, ptr
);
772 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
773 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
774 return STATUS_SUCCESS
;