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 void hid_device_send_input(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
)
82 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
87 data_size
= offsetof(RAWINPUT
, data
.hid
.bRawData
) + packet
->reportBufferLen
;
89 if (!(rawinput
= malloc(data_size
)))
91 ERR("Failed to allocate rawinput data!\n");
95 rawinput
->header
.dwType
= RIM_TYPEHID
;
96 rawinput
->header
.dwSize
= data_size
;
97 rawinput
->header
.hDevice
= ULongToHandle(ext
->u
.pdo
.rawinput_handle
);
98 rawinput
->header
.wParam
= RIM_INPUT
;
99 rawinput
->data
.hid
.dwCount
= 1;
100 rawinput
->data
.hid
.dwSizeHid
= data_size
- offsetof(RAWINPUT
, data
.hid
.bRawData
);
101 memcpy( rawinput
->data
.hid
.bRawData
, packet
->reportBuffer
, packet
->reportBufferLen
);
103 input
.type
= INPUT_HARDWARE
;
104 input
.hi
.uMsg
= WM_INPUT
;
105 input
.hi
.wParamH
= 0;
106 input
.hi
.wParamL
= 0;
107 __wine_send_input(0, &input
, rawinput
);
112 static void HID_Device_processQueue(DEVICE_OBJECT
*device
)
115 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
116 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->u
.pdo
.ring_buffer
);
117 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
118 HID_XFER_PACKET
*packet
;
120 packet
= malloc(buffer_size
);
122 while((irp
= pop_irp_from_queue(ext
)))
124 int ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
126 RingBuffer_Read(ext
->u
.pdo
.ring_buffer
, ptr
, packet
, &buffer_size
);
129 TRACE_(hid_report
)("Processing Request (%i)\n",ptr
);
130 memcpy( irp
->AssociatedIrp
.SystemBuffer
, packet
+ 1, data
->caps
.InputReportByteLength
);
131 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
132 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
136 irp
->IoStatus
.Information
= 0;
137 irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
139 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
144 static DWORD CALLBACK
hid_device_thread(void *args
)
146 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
147 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
148 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
149 BYTE report_id
= HID_INPUT_VALUE_CAPS( data
)->report_id
;
150 ULONG buffer_len
= data
->caps
.InputReportByteLength
;
152 HID_XFER_PACKET
*packet
;
156 packet
= malloc( sizeof(*packet
) + buffer_len
);
157 buffer
= (BYTE
*)(packet
+ 1);
158 packet
->reportBuffer
= buffer
;
160 if (ext
->u
.pdo
.information
.Polled
)
164 packet
->reportId
= buffer
[0] = report_id
;
165 packet
->reportBufferLen
= buffer_len
;
169 packet
->reportBuffer
++;
170 packet
->reportBufferLen
--;
173 call_minidriver( IOCTL_HID_GET_INPUT_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, packet
,
174 sizeof(*packet
), &io
);
176 if (io
.Status
== STATUS_SUCCESS
)
178 if (!report_id
) io
.Information
++;
179 packet
->reportId
= buffer
[0];
180 packet
->reportBuffer
= buffer
;
181 packet
->reportBufferLen
= io
.Information
;
183 RingBuffer_Write(ext
->u
.pdo
.ring_buffer
, packet
);
184 hid_device_send_input(device
, packet
);
185 HID_Device_processQueue(device
);
188 rc
= WaitForSingleObject(ext
->u
.pdo
.halt_event
,
189 ext
->u
.pdo
.poll_interval
? ext
->u
.pdo
.poll_interval
: DEFAULT_POLL_INTERVAL
);
191 if (rc
== WAIT_OBJECT_0
)
193 else if (rc
!= WAIT_TIMEOUT
)
194 ERR("Wait returned unexpected value %x\n",rc
);
199 INT exit_now
= FALSE
;
203 packet
->reportId
= buffer
[0] = report_id
;
204 packet
->reportBufferLen
= buffer_len
;
208 packet
->reportBuffer
++;
209 packet
->reportBufferLen
--;
212 call_minidriver( IOCTL_HID_READ_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0,
213 packet
->reportBuffer
, packet
->reportBufferLen
, &io
);
215 rc
= WaitForSingleObject(ext
->u
.pdo
.halt_event
, 0);
216 if (rc
== WAIT_OBJECT_0
)
219 if (!exit_now
&& io
.Status
== STATUS_SUCCESS
)
221 if (!report_id
) io
.Information
++;
222 packet
->reportId
= buffer
[0];
223 packet
->reportBuffer
= buffer
;
224 packet
->reportBufferLen
= io
.Information
;
226 RingBuffer_Write(ext
->u
.pdo
.ring_buffer
, packet
);
227 hid_device_send_input(device
, packet
);
228 HID_Device_processQueue(device
);
236 TRACE("Device thread exiting\n");
240 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
242 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
243 ext
->u
.pdo
.halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
244 ext
->u
.pdo
.thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
247 static void handle_IOCTL_HID_GET_COLLECTION_INFORMATION( IRP
*irp
, BASE_DEVICE_EXTENSION
*ext
)
249 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
250 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
252 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
253 irp
->IoStatus
.Information
= 0;
257 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &ext
->u
.pdo
.information
, sizeof(HID_COLLECTION_INFORMATION
));
258 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
259 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
263 static void handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( IRP
*irp
, BASE_DEVICE_EXTENSION
*ext
)
265 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
266 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
268 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< data
->dwSize
)
270 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
271 irp
->IoStatus
.Information
= 0;
275 memcpy(irp
->UserBuffer
, data
, data
->dwSize
);
276 irp
->IoStatus
.Information
= data
->dwSize
;
277 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
281 static void handle_minidriver_string( BASE_DEVICE_EXTENSION
*ext
, IRP
*irp
, SHORT index
)
283 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
287 InputBuffer
= MAKELONG(index
, 0);
289 call_minidriver( IOCTL_HID_GET_STRING
, ext
->u
.pdo
.parent_fdo
, ULongToPtr( InputBuffer
),
290 sizeof(InputBuffer
), buffer
, sizeof(buffer
), &irp
->IoStatus
);
292 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
294 WCHAR
*out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
295 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
296 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
297 lstrcpynW(out_buffer
, buffer
, length
);
298 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
302 static void hid_device_xfer_report( BASE_DEVICE_EXTENSION
*ext
, ULONG code
, IRP
*irp
)
304 WINE_HIDP_PREPARSED_DATA
*preparsed
= ext
->u
.pdo
.preparsed_data
;
305 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation( irp
);
306 struct hid_value_caps
*caps
= NULL
, *caps_end
= NULL
;
307 ULONG report_len
= 0, buffer_len
= 0;
308 HID_XFER_PACKET packet
;
313 case IOCTL_HID_GET_FEATURE
:
314 case IOCTL_HID_GET_INPUT_REPORT
:
315 buffer_len
= stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
316 buffer
= MmGetSystemAddressForMdlSafe( irp
->MdlAddress
, NormalPagePriority
);
318 case IOCTL_HID_SET_FEATURE
:
319 case IOCTL_HID_SET_OUTPUT_REPORT
:
320 buffer_len
= stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
321 buffer
= irp
->AssociatedIrp
.SystemBuffer
;
323 case IOCTL_HID_WRITE_REPORT
:
324 buffer_len
= stack
->Parameters
.Write
.Length
;
325 buffer
= irp
->AssociatedIrp
.SystemBuffer
;
331 case IOCTL_HID_GET_INPUT_REPORT
:
332 report_len
= preparsed
->caps
.InputReportByteLength
;
333 caps
= HID_INPUT_VALUE_CAPS( preparsed
);
334 caps_end
= caps
+ preparsed
->value_caps_count
[HidP_Input
];
336 case IOCTL_HID_SET_OUTPUT_REPORT
:
337 case IOCTL_HID_WRITE_REPORT
:
338 report_len
= preparsed
->caps
.OutputReportByteLength
;
339 caps
= HID_OUTPUT_VALUE_CAPS( preparsed
);
340 caps_end
= caps
+ preparsed
->value_caps_count
[HidP_Output
];
342 case IOCTL_HID_GET_FEATURE
:
343 case IOCTL_HID_SET_FEATURE
:
344 report_len
= preparsed
->caps
.FeatureReportByteLength
;
345 caps
= HID_FEATURE_VALUE_CAPS( preparsed
);
346 caps_end
= caps
+ preparsed
->value_caps_count
[HidP_Feature
];
350 if (!buffer
|| !buffer_len
)
352 irp
->IoStatus
.Status
= STATUS_INVALID_USER_BUFFER
;
355 if (buffer_len
< report_len
)
357 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
361 for (; caps
!= caps_end
; ++caps
) if (!caps
->report_id
|| caps
->report_id
== buffer
[0]) break;
362 if (caps
== caps_end
)
364 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
368 packet
.reportId
= buffer
[0];
369 packet
.reportBuffer
= buffer
;
370 packet
.reportBufferLen
= buffer_len
;
372 if (!caps
->report_id
)
375 packet
.reportBuffer
++;
376 packet
.reportBufferLen
--;
381 case IOCTL_HID_GET_FEATURE
:
382 case IOCTL_HID_GET_INPUT_REPORT
:
383 call_minidriver( code
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
), &irp
->IoStatus
);
385 case IOCTL_HID_SET_FEATURE
:
386 case IOCTL_HID_SET_OUTPUT_REPORT
:
387 case IOCTL_HID_WRITE_REPORT
:
388 call_minidriver( code
, ext
->u
.pdo
.parent_fdo
, NULL
, sizeof(packet
), &packet
, 0, &irp
->IoStatus
);
389 if (code
== IOCTL_HID_WRITE_REPORT
&& packet
.reportId
) irp
->IoStatus
.Information
--;
394 NTSTATUS WINAPI
pdo_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
396 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
397 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
403 irp
->IoStatus
.Information
= 0;
405 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
407 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
408 removed
= ext
->u
.pdo
.removed
;
409 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
413 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
414 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
415 return STATUS_DELETE_PENDING
;
418 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
420 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
421 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
422 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
424 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
425 irp
->IoStatus
.Information
= 0;
428 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.poll_interval
;
429 irp
->IoStatus
.Information
= sizeof(ULONG
);
430 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
432 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
435 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
436 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
438 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
441 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
442 if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
444 ext
->u
.pdo
.poll_interval
= poll_interval
;
445 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
448 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
451 case IOCTL_HID_GET_PRODUCT_STRING
:
453 handle_minidriver_string( ext
, irp
, HID_STRING_ID_IPRODUCT
);
456 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
458 handle_minidriver_string( ext
, irp
, HID_STRING_ID_ISERIALNUMBER
);
461 case IOCTL_HID_GET_MANUFACTURER_STRING
:
463 handle_minidriver_string( ext
, irp
, HID_STRING_ID_IMANUFACTURER
);
466 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
468 handle_IOCTL_HID_GET_COLLECTION_INFORMATION( irp
, ext
);
471 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
473 handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( irp
, ext
);
476 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
478 irp
->IoStatus
.Information
= 0;
480 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
481 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
483 irp
->IoStatus
.Status
= RingBuffer_SetSize( ext
->u
.pdo
.ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
486 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
488 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
490 irp
->IoStatus
.Information
= 0;
491 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
495 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(ext
->u
.pdo
.ring_buffer
);
496 irp
->IoStatus
.Information
= sizeof(ULONG
);
497 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
501 case IOCTL_HID_GET_FEATURE
:
502 case IOCTL_HID_SET_FEATURE
:
503 case IOCTL_HID_GET_INPUT_REPORT
:
504 case IOCTL_HID_SET_OUTPUT_REPORT
:
505 hid_device_xfer_report( ext
, code
, irp
);
509 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
510 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
511 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
512 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
517 status
= irp
->IoStatus
.Status
;
518 if (status
!= STATUS_PENDING
) IoCompleteRequest( irp
, IO_NO_INCREMENT
);
522 NTSTATUS WINAPI
pdo_read(DEVICE_OBJECT
*device
, IRP
*irp
)
524 HID_XFER_PACKET
*packet
;
525 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
526 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
527 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->u
.pdo
.ring_buffer
);
528 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
529 BYTE report_id
= HID_INPUT_VALUE_CAPS( data
)->report_id
;
535 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
536 removed
= ext
->u
.pdo
.removed
;
537 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
541 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
542 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
543 return STATUS_DELETE_PENDING
;
546 if (irpsp
->Parameters
.Read
.Length
< data
->caps
.InputReportByteLength
)
548 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
549 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
550 return STATUS_INVALID_BUFFER_SIZE
;
553 packet
= malloc(buffer_size
);
554 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
556 irp
->IoStatus
.Information
= 0;
557 RingBuffer_ReadNew(ext
->u
.pdo
.ring_buffer
, ptr
, packet
, &buffer_size
);
561 memcpy( irp
->AssociatedIrp
.SystemBuffer
, packet
+ 1, data
->caps
.InputReportByteLength
);
562 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
563 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
567 if (ext
->u
.pdo
.poll_interval
)
570 TRACE_(hid_report
)("Queue irp\n");
572 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
574 IoSetCancelRoutine(irp
, read_cancel_routine
);
575 if (irp
->Cancel
&& !IoSetCancelRoutine(irp
, NULL
))
577 /* IRP was canceled before we set cancel routine */
578 InitializeListHead(&irp
->Tail
.Overlay
.ListEntry
);
579 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
580 return STATUS_CANCELLED
;
583 InsertTailList(&ext
->u
.pdo
.irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
584 irp
->IoStatus
.Status
= STATUS_PENDING
;
585 IoMarkIrpPending(irp
);
587 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
591 HID_XFER_PACKET packet
;
592 BYTE
*buffer
= irp
->AssociatedIrp
.SystemBuffer
;
593 ULONG buffer_len
= irpsp
->Parameters
.Read
.Length
;
595 TRACE("No packet, but opportunistic reads enabled\n");
597 packet
.reportId
= buffer
[0];
598 packet
.reportBuffer
= buffer
;
599 packet
.reportBufferLen
= buffer_len
;
604 packet
.reportBuffer
++;
605 packet
.reportBufferLen
--;
608 call_minidriver( IOCTL_HID_GET_INPUT_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
,
609 sizeof(packet
), &irp
->IoStatus
);
614 status
= irp
->IoStatus
.Status
;
615 if (status
!= STATUS_PENDING
) IoCompleteRequest( irp
, IO_NO_INCREMENT
);
619 NTSTATUS WINAPI
pdo_write(DEVICE_OBJECT
*device
, IRP
*irp
)
621 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
624 hid_device_xfer_report( ext
, IOCTL_HID_WRITE_REPORT
, irp
);
626 status
= irp
->IoStatus
.Status
;
627 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
631 NTSTATUS WINAPI
pdo_create(DEVICE_OBJECT
*device
, IRP
*irp
)
633 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
635 TRACE("Open handle on device %p\n", device
);
636 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->u
.pdo
.ring_buffer
));
637 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
638 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
639 return STATUS_SUCCESS
;
642 NTSTATUS WINAPI
pdo_close(DEVICE_OBJECT
*device
, IRP
*irp
)
644 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
645 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
646 TRACE("Close handle on device %p\n", device
);
647 RingBuffer_RemovePointer(ext
->u
.pdo
.ring_buffer
, ptr
);
648 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
649 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
650 return STATUS_SUCCESS
;