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 "ddk/hidsdi.h"
28 #include "ddk/hidtypes.h"
31 #include "wine/debug.h"
32 #include "wine/list.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
36 static void WINAPI
read_cancel_routine(DEVICE_OBJECT
*device
, IRP
*irp
)
38 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
41 TRACE("cancel %p IRP on device %p\n", irp
, device
);
43 IoReleaseCancelSpinLock(irp
->CancelIrql
);
45 KeAcquireSpinLock( &queue
->lock
, &irql
);
47 RemoveEntryList(&irp
->Tail
.Overlay
.ListEntry
);
49 KeReleaseSpinLock( &queue
->lock
, irql
);
51 irp
->IoStatus
.Status
= STATUS_CANCELLED
;
52 irp
->IoStatus
.Information
= 0;
53 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
56 static struct hid_report
*hid_report_create( HID_XFER_PACKET
*packet
, ULONG length
)
58 struct hid_report
*report
;
60 if (!(report
= malloc( offsetof( struct hid_report
, buffer
[length
] ) )))
63 report
->length
= length
;
64 memcpy( report
->buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
65 memset( report
->buffer
+ packet
->reportBufferLen
, 0, length
- packet
->reportBufferLen
);
70 static void hid_report_incref( struct hid_report
*report
)
72 InterlockedIncrement( &report
->ref
);
75 static void hid_report_decref( struct hid_report
*report
)
78 if (InterlockedDecrement( &report
->ref
) == 0) free( report
);
81 static struct hid_queue
*hid_queue_create( void )
83 struct hid_queue
*queue
;
85 if (!(queue
= calloc( 1, sizeof(struct hid_queue
) ))) return NULL
;
86 InitializeListHead( &queue
->irp_queue
);
87 KeInitializeSpinLock( &queue
->lock
);
88 list_init( &queue
->entry
);
96 static IRP
*hid_queue_pop_irp( struct hid_queue
*queue
)
102 KeAcquireSpinLock( &queue
->lock
, &irql
);
104 while (!irp
&& (entry
= RemoveHeadList( &queue
->irp_queue
)) != &queue
->irp_queue
)
106 irp
= CONTAINING_RECORD( entry
, IRP
, Tail
.Overlay
.ListEntry
);
107 if (!IoSetCancelRoutine( irp
, NULL
))
109 /* cancel routine is already cleared, meaning that it was called. let it handle completion. */
110 InitializeListHead( &irp
->Tail
.Overlay
.ListEntry
);
115 KeReleaseSpinLock( &queue
->lock
, irql
);
119 void hid_queue_remove_pending_irps( struct hid_queue
*queue
)
123 while ((irp
= hid_queue_pop_irp( queue
)))
125 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
126 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
130 void hid_queue_destroy( struct hid_queue
*queue
)
132 hid_queue_remove_pending_irps( queue
);
133 while (queue
->length
--) hid_report_decref( queue
->reports
[queue
->length
] );
134 list_remove( &queue
->entry
);
138 static NTSTATUS
hid_queue_resize( struct hid_queue
*queue
, ULONG length
)
140 struct hid_report
*old_reports
[512];
141 LONG old_length
= queue
->length
;
144 if (length
< 2 || length
> 512) return STATUS_INVALID_PARAMETER
;
145 if (length
== queue
->length
) return STATUS_SUCCESS
;
147 KeAcquireSpinLock( &queue
->lock
, &irql
);
148 memcpy( old_reports
, queue
->reports
, old_length
* sizeof(void *) );
149 memset( queue
->reports
, 0, old_length
* sizeof(void *) );
150 queue
->length
= length
;
151 queue
->write_idx
= 0;
153 KeReleaseSpinLock( &queue
->lock
, irql
);
155 while (old_length
--) hid_report_decref( old_reports
[old_length
] );
156 return STATUS_SUCCESS
;
159 static NTSTATUS
hid_queue_push_irp( struct hid_queue
*queue
, IRP
*irp
)
163 KeAcquireSpinLock( &queue
->lock
, &irql
);
165 IoSetCancelRoutine( irp
, read_cancel_routine
);
166 if (irp
->Cancel
&& !IoSetCancelRoutine( irp
, NULL
))
168 /* IRP was canceled before we set cancel routine */
169 InitializeListHead( &irp
->Tail
.Overlay
.ListEntry
);
170 KeReleaseSpinLock( &queue
->lock
, irql
);
171 return STATUS_CANCELLED
;
174 InsertTailList( &queue
->irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
175 irp
->IoStatus
.Status
= STATUS_PENDING
;
176 IoMarkIrpPending( irp
);
178 KeReleaseSpinLock( &queue
->lock
, irql
);
179 return STATUS_PENDING
;
182 static void hid_queue_push_report( struct hid_queue
*queue
, struct hid_report
*report
)
184 ULONG i
= queue
->write_idx
, next
= i
+ 1;
185 struct hid_report
*prev
;
188 if (next
>= queue
->length
) next
= 0;
189 hid_report_incref( report
);
191 KeAcquireSpinLock( &queue
->lock
, &irql
);
192 prev
= queue
->reports
[i
];
193 queue
->reports
[i
] = report
;
194 if (next
== queue
->read_idx
) queue
->read_idx
= next
+ 1;
195 if (queue
->read_idx
>= queue
->length
) queue
->read_idx
= 0;
196 KeReleaseSpinLock( &queue
->lock
, irql
);
198 hid_report_decref( prev
);
199 queue
->write_idx
= next
;
202 static struct hid_report
*hid_queue_pop_report( struct hid_queue
*queue
)
204 ULONG i
= queue
->read_idx
, next
= i
+ 1;
205 struct hid_report
*report
;
208 if (next
>= queue
->length
) next
= 0;
210 KeAcquireSpinLock( &queue
->lock
, &irql
);
211 report
= queue
->reports
[i
];
212 queue
->reports
[i
] = NULL
;
213 if (i
!= queue
->write_idx
) queue
->read_idx
= next
;
214 KeReleaseSpinLock( &queue
->lock
, irql
);
219 static void hid_device_queue_input( DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
)
221 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
222 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
223 const BOOL polled
= ext
->u
.pdo
.information
.Polled
;
224 ULONG size
, report_len
= polled
? packet
->reportBufferLen
: desc
->InputLength
;
225 struct hid_report
*last_report
, *report
;
226 struct hid_queue
*queue
;
227 LIST_ENTRY completed
, *entry
;
231 TRACE("device %p, packet %p\n", device
, packet
);
233 if (IsEqualGUID( ext
->class_guid
, &GUID_DEVINTERFACE_HID
))
235 struct hid_packet
*hid
;
237 size
= offsetof( struct hid_packet
, data
[report_len
] );
238 if (!(hid
= malloc( size
))) ERR( "Failed to allocate rawinput data!\n" );
241 INPUT input
= {.type
= INPUT_HARDWARE
};
243 input
.hi
.uMsg
= WM_INPUT
;
244 input
.hi
.wParamH
= HIWORD(RIM_INPUT
);
245 input
.hi
.wParamL
= LOWORD(RIM_INPUT
);
247 hid
->head
.device
= ext
->u
.pdo
.rawinput_handle
;
248 hid
->head
.usage
= MAKELONG(desc
->Usage
, desc
->UsagePage
);
251 hid
->head
.length
= report_len
;
252 memcpy( hid
->data
, packet
->reportBuffer
, packet
->reportBufferLen
);
253 memset( hid
->data
+ packet
->reportBufferLen
, 0, report_len
- packet
->reportBufferLen
);
254 NtUserSendHardwareInput( 0, 0, &input
, (LPARAM
)hid
);
260 if (!(last_report
= hid_report_create( packet
, report_len
)))
262 ERR( "Failed to allocate hid_report!\n" );
266 InitializeListHead( &completed
);
268 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
269 LIST_FOR_EACH_ENTRY( queue
, &ext
->u
.pdo
.queues
, struct hid_queue
, entry
)
271 if (!polled
) hid_queue_push_report( queue
, last_report
);
275 if (!(irp
= hid_queue_pop_irp( queue
))) break;
276 if (!(report
= hid_queue_pop_report( queue
))) hid_report_incref( (report
= last_report
) );
278 memcpy( irp
->AssociatedIrp
.SystemBuffer
, report
->buffer
, report
->length
);
279 irp
->IoStatus
.Information
= report
->length
;
280 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
281 hid_report_decref( report
);
283 InsertTailList( &completed
, &irp
->Tail
.Overlay
.ListEntry
);
287 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
289 while ((entry
= RemoveHeadList( &completed
)) != &completed
)
291 irp
= CONTAINING_RECORD( entry
, IRP
, Tail
.Overlay
.ListEntry
);
292 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
295 hid_report_decref( last_report
);
298 static HIDP_REPORT_IDS
*find_report_with_type_and_id( BASE_DEVICE_EXTENSION
*ext
, BYTE type
, BYTE id
, BOOL any_id
)
300 HIDP_REPORT_IDS
*report
, *reports
= ext
->u
.pdo
.device_desc
.ReportIDs
;
301 ULONG report_count
= ext
->u
.pdo
.device_desc
.ReportIDsLength
;
303 for (report
= reports
; report
!= reports
+ report_count
; report
++)
305 if (!any_id
&& report
->ReportID
&& report
->ReportID
!= id
) continue;
306 if (type
== HidP_Input
&& report
->InputLength
) return report
;
307 if (type
== HidP_Output
&& report
->OutputLength
) return report
;
308 if (type
== HidP_Feature
&& report
->FeatureLength
) return report
;
314 static DWORD CALLBACK
hid_device_thread(void *args
)
316 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
317 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
318 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
319 BOOL polled
= ext
->u
.pdo
.information
.Polled
;
320 HIDP_REPORT_IDS
*report
;
321 HID_XFER_PACKET
*packet
;
327 packet
= malloc( sizeof(*packet
) + desc
->InputLength
);
328 buffer
= (BYTE
*)(packet
+ 1);
330 report
= find_report_with_type_and_id( ext
, HidP_Input
, 0, TRUE
);
331 if (!report
) WARN("no input report found.\n");
332 else report_id
= report
->ReportID
;
336 packet
->reportId
= buffer
[0] = report_id
;
337 packet
->reportBuffer
= buffer
;
338 packet
->reportBufferLen
= desc
->InputLength
;
342 packet
->reportBuffer
++;
343 packet
->reportBufferLen
--;
346 call_minidriver( IOCTL_HID_READ_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0,
347 packet
->reportBuffer
, packet
->reportBufferLen
, &io
);
349 if (io
.Status
== STATUS_SUCCESS
)
351 if (!report_id
) io
.Information
++;
352 if (!(report
= find_report_with_type_and_id( ext
, HidP_Input
, buffer
[0], FALSE
)))
353 WARN( "dropping unknown input id %u\n", buffer
[0] );
354 else if (!polled
&& io
.Information
< report
->InputLength
)
355 WARN( "dropping short report, len %Iu expected %u\n", io
.Information
, report
->InputLength
);
358 packet
->reportId
= buffer
[0];
359 packet
->reportBuffer
= buffer
;
360 packet
->reportBufferLen
= io
.Information
;
361 hid_device_queue_input( device
, packet
);
365 res
= WaitForSingleObject(ext
->u
.pdo
.halt_event
, polled
? ext
->u
.pdo
.poll_interval
: 0);
366 } while (res
== WAIT_TIMEOUT
);
368 TRACE( "device thread exiting, res %#lx\n", res
);
372 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
374 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
375 ext
->u
.pdo
.halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
376 ext
->u
.pdo
.thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
379 struct device_strings
382 const WCHAR
*product
;
385 static const struct device_strings device_strings
[] =
387 /* Microsoft controllers */
388 { .id
= L
"VID_045E&PID_028E", .product
= L
"Controller (XBOX 360 For Windows)" },
389 { .id
= L
"VID_045E&PID_028F", .product
= L
"Controller (XBOX 360 For Windows)" },
390 { .id
= L
"VID_045E&PID_02D1", .product
= L
"Controller (Xbox One For Windows)" },
391 { .id
= L
"VID_045E&PID_02DD", .product
= L
"Controller (Xbox One For Windows)" },
392 { .id
= L
"VID_045E&PID_02E3", .product
= L
"Controller (Xbox One For Windows)" },
393 { .id
= L
"VID_045E&PID_02EA", .product
= L
"Controller (Xbox One For Windows)" },
394 { .id
= L
"VID_045E&PID_02FD", .product
= L
"Controller (Xbox One For Windows)" },
395 { .id
= L
"VID_045E&PID_0719", .product
= L
"Controller (XBOX 360 For Windows)" },
396 { .id
= L
"VID_045E&PID_0B00", .product
= L
"Controller (Xbox One For Windows)" },
397 { .id
= L
"VID_045E&PID_0B05", .product
= L
"Controller (Xbox One For Windows)" },
398 { .id
= L
"VID_045E&PID_0B12", .product
= L
"Controller (Xbox One For Windows)" },
399 { .id
= L
"VID_045E&PID_0B13", .product
= L
"Controller (Xbox One For Windows)" },
400 /* Sony controllers */
401 { .id
= L
"VID_054C&PID_05C4", .product
= L
"Wireless Controller" },
402 { .id
= L
"VID_054C&PID_09CC", .product
= L
"Wireless Controller" },
403 { .id
= L
"VID_054C&PID_0BA0", .product
= L
"Wireless Controller" },
404 { .id
= L
"VID_054C&PID_0CE6", .product
= L
"Wireless Controller" },
405 { .id
= L
"VID_054C&PID_0DF2", .product
= L
"Wireless Controller" },
408 static const WCHAR
*find_device_string( const WCHAR
*device_id
, ULONG index
)
410 const WCHAR
*match_id
= wcsrchr( device_id
, '\\' ) + 1;
413 if (index
!= HID_STRING_ID_IPRODUCT
) return NULL
;
415 for (i
= 0; i
< ARRAY_SIZE(device_strings
); ++i
)
416 if (!wcsnicmp( device_strings
[i
].id
, match_id
, 17 ))
417 return device_strings
[i
].product
;
422 struct completion_params
424 HID_XFER_PACKET packet
;
429 static NTSTATUS CALLBACK
xfer_completion( DEVICE_OBJECT
*device
, IRP
*irp
, void *context
)
431 struct completion_params
*params
= context
;
432 IRP
*orig_irp
= params
->irp
;
434 TRACE( "device %p, irp %p, context %p\n", device
, irp
, context
);
436 orig_irp
->IoStatus
= irp
->IoStatus
;
437 orig_irp
->IoStatus
.Information
-= params
->padding
;
438 IoCompleteRequest( orig_irp
, IO_NO_INCREMENT
);
441 return STATUS_SUCCESS
;
444 static NTSTATUS
hid_device_xfer_report( BASE_DEVICE_EXTENSION
*ext
, ULONG code
, IRP
*irp
)
446 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation( irp
);
447 ULONG offset
, report_len
= 0, buffer_len
= 0;
448 struct completion_params
*params
;
449 HIDP_REPORT_IDS
*report
= NULL
;
454 case IOCTL_HID_GET_FEATURE
:
455 case IOCTL_HID_GET_INPUT_REPORT
:
456 buffer_len
= stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
457 buffer
= MmGetSystemAddressForMdlSafe( irp
->MdlAddress
, NormalPagePriority
);
459 case IOCTL_HID_SET_FEATURE
:
460 case IOCTL_HID_SET_OUTPUT_REPORT
:
461 buffer_len
= stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
462 buffer
= irp
->AssociatedIrp
.SystemBuffer
;
464 case IOCTL_HID_WRITE_REPORT
:
465 buffer_len
= stack
->Parameters
.Write
.Length
;
466 buffer
= irp
->AssociatedIrp
.SystemBuffer
;
469 if (!buffer
|| !buffer_len
) return STATUS_INVALID_USER_BUFFER
;
473 case IOCTL_HID_GET_INPUT_REPORT
:
474 report
= find_report_with_type_and_id( ext
, HidP_Input
, buffer
[0], FALSE
);
475 if (report
) report_len
= report
->InputLength
;
477 case IOCTL_HID_SET_OUTPUT_REPORT
:
478 case IOCTL_HID_WRITE_REPORT
:
479 report
= find_report_with_type_and_id( ext
, HidP_Output
, buffer
[0], FALSE
);
480 if (report
) report_len
= report
->OutputLength
;
482 case IOCTL_HID_GET_FEATURE
:
483 case IOCTL_HID_SET_FEATURE
:
484 report
= find_report_with_type_and_id( ext
, HidP_Feature
, buffer
[0], FALSE
);
485 if (report
) report_len
= report
->FeatureLength
;
488 if (!report
|| buffer_len
< report_len
) return STATUS_INVALID_PARAMETER
;
489 offset
= report
->ReportID
? 0 : 1;
491 if (!(params
= calloc( 1, sizeof(struct completion_params
) ))) return STATUS_NO_MEMORY
;
492 params
->packet
.reportId
= report
->ReportID
;
493 params
->packet
.reportBuffer
= buffer
+ offset
;
498 case IOCTL_HID_GET_FEATURE
:
499 case IOCTL_HID_GET_INPUT_REPORT
:
500 params
->packet
.reportBufferLen
= buffer_len
- offset
;
501 irp
= IoBuildDeviceIoControlRequest( code
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, ¶ms
->packet
,
502 sizeof(params
->packet
), TRUE
, NULL
, NULL
);
504 case IOCTL_HID_WRITE_REPORT
:
505 params
->padding
= 1 - offset
;
507 case IOCTL_HID_SET_FEATURE
:
508 case IOCTL_HID_SET_OUTPUT_REPORT
:
509 params
->packet
.reportBufferLen
= report_len
- offset
;
510 irp
= IoBuildDeviceIoControlRequest( code
, ext
->u
.pdo
.parent_fdo
, NULL
, sizeof(params
->packet
),
511 ¶ms
->packet
, 0, TRUE
, NULL
, NULL
);
518 return STATUS_NO_MEMORY
;
521 IoMarkIrpPending( params
->irp
);
522 IoSetCompletionRoutine( irp
, xfer_completion
, params
, TRUE
, TRUE
, TRUE
);
523 IoCallDriver( ext
->u
.pdo
.parent_fdo
, irp
);
524 return STATUS_PENDING
;
527 NTSTATUS WINAPI
pdo_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
529 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
530 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
531 NTSTATUS status
= irp
->IoStatus
.Status
;
537 irp
->IoStatus
.Information
= 0;
539 TRACE( "device %p code %#lx\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
541 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
542 removed
= ext
->u
.pdo
.removed
;
543 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
547 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
548 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
549 return STATUS_DELETE_PENDING
;
552 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
554 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
555 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
556 status
= STATUS_BUFFER_OVERFLOW
;
559 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.poll_interval
;
560 irp
->IoStatus
.Information
= sizeof(ULONG
);
561 status
= STATUS_SUCCESS
;
564 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
567 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
568 status
= STATUS_BUFFER_TOO_SMALL
;
571 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
572 if (poll_interval
) ext
->u
.pdo
.poll_interval
= min( poll_interval
, MAX_POLL_INTERVAL_MSEC
);
573 status
= STATUS_SUCCESS
;
577 case IOCTL_HID_GET_PRODUCT_STRING
:
578 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
579 case IOCTL_HID_GET_MANUFACTURER_STRING
:
581 WCHAR
*output_buf
= MmGetSystemAddressForMdlSafe( irp
->MdlAddress
, NormalPagePriority
);
582 ULONG output_len
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
584 if (code
== IOCTL_HID_GET_PRODUCT_STRING
) index
= HID_STRING_ID_IPRODUCT
;
585 if (code
== IOCTL_HID_GET_SERIALNUMBER_STRING
) index
= HID_STRING_ID_ISERIALNUMBER
;
586 if (code
== IOCTL_HID_GET_MANUFACTURER_STRING
) index
= HID_STRING_ID_IMANUFACTURER
;
588 if ((str
= find_device_string( ext
->device_id
, index
)))
590 irp
->IoStatus
.Information
= (wcslen( str
) + 1) * sizeof(WCHAR
);
591 if (irp
->IoStatus
.Information
> output_len
)
592 status
= STATUS_BUFFER_TOO_SMALL
;
595 memcpy( output_buf
, str
, irp
->IoStatus
.Information
);
596 status
= STATUS_SUCCESS
;
601 call_minidriver( IOCTL_HID_GET_STRING
, ext
->u
.pdo
.parent_fdo
, ULongToPtr( index
),
602 sizeof(index
), output_buf
, output_len
, &irp
->IoStatus
);
603 status
= irp
->IoStatus
.Status
;
606 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
608 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
609 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
610 status
= STATUS_BUFFER_OVERFLOW
;
613 memcpy( irp
->AssociatedIrp
.SystemBuffer
, &ext
->u
.pdo
.information
,
614 sizeof(HID_COLLECTION_INFORMATION
) );
615 status
= STATUS_SUCCESS
;
619 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
621 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
623 irp
->IoStatus
.Information
= desc
->PreparsedDataLength
;
624 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< desc
->PreparsedDataLength
)
625 status
= STATUS_INVALID_BUFFER_SIZE
;
628 memcpy( irp
->UserBuffer
, desc
->PreparsedData
, desc
->PreparsedDataLength
);
629 status
= STATUS_SUCCESS
;
633 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
635 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
636 status
= STATUS_BUFFER_OVERFLOW
;
639 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
640 status
= hid_queue_resize( queue
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
644 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
646 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
647 status
= STATUS_BUFFER_TOO_SMALL
;
650 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
651 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= queue
->length
;
652 irp
->IoStatus
.Information
= sizeof(ULONG
);
653 status
= STATUS_SUCCESS
;
657 case IOCTL_HID_GET_FEATURE
:
658 case IOCTL_HID_SET_FEATURE
:
659 case IOCTL_HID_GET_INPUT_REPORT
:
660 case IOCTL_HID_SET_OUTPUT_REPORT
:
661 status
= hid_device_xfer_report( ext
, code
, irp
);
664 case IOCTL_HID_GET_WINE_RAWINPUT_HANDLE
:
665 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
666 status
= STATUS_BUFFER_OVERFLOW
;
669 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.rawinput_handle
;
670 irp
->IoStatus
.Information
= sizeof(ULONG
);
671 status
= STATUS_SUCCESS
;
677 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
678 FIXME( "Unsupported ioctl %#lx (device=%lx access=%lx func=%lx method=%lx)\n", code
,
679 code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3 );
680 status
= STATUS_NOT_SUPPORTED
;
685 if (status
!= STATUS_PENDING
)
687 irp
->IoStatus
.Status
= status
;
688 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
693 NTSTATUS WINAPI
pdo_read(DEVICE_OBJECT
*device
, IRP
*irp
)
695 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
696 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
697 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
698 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
699 struct hid_report
*report
;
703 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
704 removed
= ext
->u
.pdo
.removed
;
705 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
709 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
710 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
711 return STATUS_DELETE_PENDING
;
714 if (irpsp
->Parameters
.Read
.Length
< desc
->InputLength
)
716 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
717 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
718 return STATUS_INVALID_BUFFER_SIZE
;
721 irp
->IoStatus
.Information
= 0;
722 if ((report
= hid_queue_pop_report( queue
)))
724 memcpy( irp
->AssociatedIrp
.SystemBuffer
, report
->buffer
, report
->length
);
725 irp
->IoStatus
.Information
= report
->length
;
726 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
727 hid_report_decref( report
);
729 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
730 return STATUS_SUCCESS
;
733 return hid_queue_push_irp( queue
, irp
);
737 NTSTATUS WINAPI
pdo_write(DEVICE_OBJECT
*device
, IRP
*irp
)
739 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
740 NTSTATUS status
= hid_device_xfer_report( ext
, IOCTL_HID_WRITE_REPORT
, irp
);
741 if (status
!= STATUS_PENDING
)
743 irp
->IoStatus
.Status
= status
;
744 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
749 NTSTATUS WINAPI
pdo_create(DEVICE_OBJECT
*device
, IRP
*irp
)
751 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
752 struct hid_queue
*queue
;
756 TRACE("Open handle on device %p\n", device
);
758 KeAcquireSpinLock( &ext
->u
.pdo
.lock
, &irql
);
759 removed
= ext
->u
.pdo
.removed
;
760 KeReleaseSpinLock( &ext
->u
.pdo
.lock
, irql
);
764 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
765 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
766 return STATUS_DELETE_PENDING
;
769 if (!(queue
= hid_queue_create())) irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
772 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
773 list_add_tail( &ext
->u
.pdo
.queues
, &queue
->entry
);
774 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
776 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= queue
;
777 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
780 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
781 return STATUS_SUCCESS
;
784 NTSTATUS WINAPI
pdo_close(DEVICE_OBJECT
*device
, IRP
*irp
)
786 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
787 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
791 TRACE("Close handle on device %p\n", device
);
793 KeAcquireSpinLock( &ext
->u
.pdo
.lock
, &irql
);
794 removed
= ext
->u
.pdo
.removed
;
795 KeReleaseSpinLock( &ext
->u
.pdo
.lock
, irql
);
799 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
800 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
801 return STATUS_DELETE_PENDING
;
806 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
807 list_remove( &queue
->entry
);
808 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
809 hid_queue_destroy( queue
);
812 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
813 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
814 return STATUS_SUCCESS
;