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 const 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
;
327 case IOCTL_HID_GET_INPUT_REPORT
:
328 report_len
= preparsed
->caps
.InputReportByteLength
;
329 caps
= HID_INPUT_VALUE_CAPS( preparsed
);
330 caps_end
= caps
+ preparsed
->value_caps_count
[HidP_Input
];
332 case IOCTL_HID_SET_OUTPUT_REPORT
:
333 report_len
= preparsed
->caps
.OutputReportByteLength
;
334 caps
= HID_OUTPUT_VALUE_CAPS( preparsed
);
335 caps_end
= caps
+ preparsed
->value_caps_count
[HidP_Output
];
337 case IOCTL_HID_GET_FEATURE
:
338 case IOCTL_HID_SET_FEATURE
:
339 report_len
= preparsed
->caps
.FeatureReportByteLength
;
340 caps
= HID_FEATURE_VALUE_CAPS( preparsed
);
341 caps_end
= caps
+ preparsed
->value_caps_count
[HidP_Feature
];
345 if (!buffer
|| !buffer_len
)
347 irp
->IoStatus
.Status
= STATUS_INVALID_USER_BUFFER
;
350 if (buffer_len
< report_len
)
352 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
356 for (; caps
!= caps_end
; ++caps
) if (!caps
->report_id
|| caps
->report_id
== buffer
[0]) break;
357 if (caps
== caps_end
)
359 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
363 packet
.reportId
= buffer
[0];
364 packet
.reportBuffer
= buffer
;
365 packet
.reportBufferLen
= buffer_len
;
367 if (!caps
->report_id
)
370 packet
.reportBuffer
++;
371 packet
.reportBufferLen
--;
376 case IOCTL_HID_GET_FEATURE
:
377 case IOCTL_HID_GET_INPUT_REPORT
:
378 call_minidriver( code
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
), &irp
->IoStatus
);
380 case IOCTL_HID_SET_FEATURE
:
381 case IOCTL_HID_SET_OUTPUT_REPORT
:
382 call_minidriver( code
, ext
->u
.pdo
.parent_fdo
, NULL
, sizeof(packet
), &packet
, 0, &irp
->IoStatus
);
387 NTSTATUS WINAPI
pdo_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
389 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
390 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
396 irp
->IoStatus
.Information
= 0;
398 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
400 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
401 removed
= ext
->u
.pdo
.removed
;
402 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
406 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
407 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
408 return STATUS_DELETE_PENDING
;
411 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
413 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
414 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
415 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
417 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
418 irp
->IoStatus
.Information
= 0;
421 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.poll_interval
;
422 irp
->IoStatus
.Information
= sizeof(ULONG
);
423 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
425 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
428 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
429 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
431 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
434 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
435 if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
437 ext
->u
.pdo
.poll_interval
= poll_interval
;
438 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
441 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
444 case IOCTL_HID_GET_PRODUCT_STRING
:
446 handle_minidriver_string( ext
, irp
, HID_STRING_ID_IPRODUCT
);
449 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
451 handle_minidriver_string( ext
, irp
, HID_STRING_ID_ISERIALNUMBER
);
454 case IOCTL_HID_GET_MANUFACTURER_STRING
:
456 handle_minidriver_string( ext
, irp
, HID_STRING_ID_IMANUFACTURER
);
459 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
461 handle_IOCTL_HID_GET_COLLECTION_INFORMATION( irp
, ext
);
464 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
466 handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( irp
, ext
);
469 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
471 irp
->IoStatus
.Information
= 0;
473 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
474 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
476 irp
->IoStatus
.Status
= RingBuffer_SetSize( ext
->u
.pdo
.ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
479 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
481 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
483 irp
->IoStatus
.Information
= 0;
484 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
488 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(ext
->u
.pdo
.ring_buffer
);
489 irp
->IoStatus
.Information
= sizeof(ULONG
);
490 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
494 case IOCTL_HID_GET_FEATURE
:
495 case IOCTL_HID_SET_FEATURE
:
496 case IOCTL_HID_GET_INPUT_REPORT
:
497 case IOCTL_HID_SET_OUTPUT_REPORT
:
498 hid_device_xfer_report( ext
, code
, irp
);
502 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
503 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
504 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
505 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
510 status
= irp
->IoStatus
.Status
;
511 if (status
!= STATUS_PENDING
) IoCompleteRequest( irp
, IO_NO_INCREMENT
);
515 NTSTATUS WINAPI
pdo_read(DEVICE_OBJECT
*device
, IRP
*irp
)
517 HID_XFER_PACKET
*packet
;
518 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
519 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
520 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->u
.pdo
.ring_buffer
);
521 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
522 BYTE report_id
= HID_INPUT_VALUE_CAPS( data
)->report_id
;
528 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
529 removed
= ext
->u
.pdo
.removed
;
530 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
534 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
535 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
536 return STATUS_DELETE_PENDING
;
539 if (irpsp
->Parameters
.Read
.Length
< data
->caps
.InputReportByteLength
)
541 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
542 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
543 return STATUS_INVALID_BUFFER_SIZE
;
546 packet
= malloc(buffer_size
);
547 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
549 irp
->IoStatus
.Information
= 0;
550 RingBuffer_ReadNew(ext
->u
.pdo
.ring_buffer
, ptr
, packet
, &buffer_size
);
554 memcpy( irp
->AssociatedIrp
.SystemBuffer
, packet
+ 1, data
->caps
.InputReportByteLength
);
555 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
556 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
560 if (ext
->u
.pdo
.poll_interval
)
563 TRACE_(hid_report
)("Queue irp\n");
565 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
567 IoSetCancelRoutine(irp
, read_cancel_routine
);
568 if (irp
->Cancel
&& !IoSetCancelRoutine(irp
, NULL
))
570 /* IRP was canceled before we set cancel routine */
571 InitializeListHead(&irp
->Tail
.Overlay
.ListEntry
);
572 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
573 return STATUS_CANCELLED
;
576 InsertTailList(&ext
->u
.pdo
.irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
577 irp
->IoStatus
.Status
= STATUS_PENDING
;
578 IoMarkIrpPending(irp
);
580 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
584 HID_XFER_PACKET packet
;
585 BYTE
*buffer
= irp
->AssociatedIrp
.SystemBuffer
;
586 ULONG buffer_len
= irpsp
->Parameters
.Read
.Length
;
588 TRACE("No packet, but opportunistic reads enabled\n");
590 packet
.reportId
= buffer
[0];
591 packet
.reportBuffer
= buffer
;
592 packet
.reportBufferLen
= buffer_len
;
597 packet
.reportBuffer
++;
598 packet
.reportBufferLen
--;
601 call_minidriver( IOCTL_HID_GET_INPUT_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
,
602 sizeof(packet
), &irp
->IoStatus
);
607 status
= irp
->IoStatus
.Status
;
608 if (status
!= STATUS_PENDING
) IoCompleteRequest( irp
, IO_NO_INCREMENT
);
612 NTSTATUS WINAPI
pdo_write(DEVICE_OBJECT
*device
, IRP
*irp
)
614 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
615 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
616 const WINE_HIDP_PREPARSED_DATA
*data
= ext
->u
.pdo
.preparsed_data
;
617 HID_XFER_PACKET packet
;
623 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
624 removed
= ext
->u
.pdo
.removed
;
625 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
629 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
630 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
631 return STATUS_DELETE_PENDING
;
634 if (!irpsp
->Parameters
.Write
.Length
)
636 irp
->IoStatus
.Status
= STATUS_INVALID_USER_BUFFER
;
637 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
638 return STATUS_INVALID_USER_BUFFER
;
641 if (irpsp
->Parameters
.Write
.Length
< data
->caps
.OutputReportByteLength
)
643 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
644 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
645 return STATUS_INVALID_PARAMETER
;
648 irp
->IoStatus
.Information
= 0;
650 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
651 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
652 if (packet
.reportId
== 0)
654 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
655 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
- 1;
656 max_len
= data
->caps
.OutputReportByteLength
;
660 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
661 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
662 max_len
= (data
->reports
[data
->reportIdx
[HidP_Output
][packet
.reportId
]].bitSize
+ 7) / 8;
664 if (packet
.reportBufferLen
> max_len
)
665 packet
.reportBufferLen
= max_len
;
667 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
669 call_minidriver( IOCTL_HID_WRITE_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
,
670 sizeof(packet
), &irp
->IoStatus
);
672 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
673 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
675 irp
->IoStatus
.Information
= 0;
677 TRACE_(hid_report
)( "Result 0x%x wrote %li bytes\n", irp
->IoStatus
.Status
, irp
->IoStatus
.Information
);
679 status
= irp
->IoStatus
.Status
;
680 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
684 NTSTATUS WINAPI
pdo_create(DEVICE_OBJECT
*device
, IRP
*irp
)
686 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
688 TRACE("Open handle on device %p\n", device
);
689 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->u
.pdo
.ring_buffer
));
690 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
691 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
692 return STATUS_SUCCESS
;
695 NTSTATUS WINAPI
pdo_close(DEVICE_OBJECT
*device
, IRP
*irp
)
697 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
698 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
699 TRACE("Close handle on device %p\n", device
);
700 RingBuffer_RemovePointer(ext
->u
.pdo
.ring_buffer
, ptr
);
701 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
702 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
703 return STATUS_SUCCESS
;