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
;
232 TRACE("device %p, packet %p\n", device
, packet
);
234 if (IsEqualGUID( ext
->class_guid
, &GUID_DEVINTERFACE_HID
))
236 size
= offsetof( RAWINPUT
, data
.hid
.bRawData
[report_len
] );
237 if (!(rawinput
= malloc( size
))) ERR( "Failed to allocate rawinput data!\n" );
242 rawinput
->header
.dwType
= RIM_TYPEHID
;
243 rawinput
->header
.dwSize
= size
;
244 rawinput
->header
.hDevice
= ULongToHandle( ext
->u
.pdo
.rawinput_handle
);
245 rawinput
->header
.wParam
= RIM_INPUT
;
246 rawinput
->data
.hid
.dwCount
= 1;
247 rawinput
->data
.hid
.dwSizeHid
= report_len
;
248 memcpy( rawinput
->data
.hid
.bRawData
, packet
->reportBuffer
, packet
->reportBufferLen
);
249 memset( rawinput
->data
.hid
.bRawData
+ packet
->reportBufferLen
, 0, report_len
- packet
->reportBufferLen
);
251 input
.type
= INPUT_HARDWARE
;
252 input
.hi
.uMsg
= WM_INPUT
;
253 input
.hi
.wParamH
= 0;
254 input
.hi
.wParamL
= 0;
255 __wine_send_input( 0, &input
, rawinput
);
261 if (!(last_report
= hid_report_create( packet
, report_len
)))
263 ERR( "Failed to allocate hid_report!\n" );
267 InitializeListHead( &completed
);
269 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
270 LIST_FOR_EACH_ENTRY( queue
, &ext
->u
.pdo
.queues
, struct hid_queue
, entry
)
272 if (!polled
) hid_queue_push_report( queue
, last_report
);
276 if (!(irp
= hid_queue_pop_irp( queue
))) break;
277 if (!(report
= hid_queue_pop_report( queue
))) hid_report_incref( (report
= last_report
) );
279 memcpy( irp
->AssociatedIrp
.SystemBuffer
, report
->buffer
, report
->length
);
280 irp
->IoStatus
.Information
= report
->length
;
281 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
282 hid_report_decref( report
);
284 InsertTailList( &completed
, &irp
->Tail
.Overlay
.ListEntry
);
288 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
290 while ((entry
= RemoveHeadList( &completed
)) != &completed
)
292 irp
= CONTAINING_RECORD( entry
, IRP
, Tail
.Overlay
.ListEntry
);
293 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
296 hid_report_decref( last_report
);
299 static HIDP_REPORT_IDS
*find_report_with_type_and_id( BASE_DEVICE_EXTENSION
*ext
, BYTE type
, BYTE id
, BOOL any_id
)
301 HIDP_REPORT_IDS
*report
, *reports
= ext
->u
.pdo
.device_desc
.ReportIDs
;
302 ULONG report_count
= ext
->u
.pdo
.device_desc
.ReportIDsLength
;
304 for (report
= reports
; report
!= reports
+ report_count
; report
++)
306 if (!any_id
&& report
->ReportID
&& report
->ReportID
!= id
) continue;
307 if (type
== HidP_Input
&& report
->InputLength
) return report
;
308 if (type
== HidP_Output
&& report
->OutputLength
) return report
;
309 if (type
== HidP_Feature
&& report
->FeatureLength
) return report
;
315 static DWORD CALLBACK
hid_device_thread(void *args
)
317 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
318 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
319 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
320 BOOL polled
= ext
->u
.pdo
.information
.Polled
;
321 HIDP_REPORT_IDS
*report
;
322 HID_XFER_PACKET
*packet
;
328 packet
= malloc( sizeof(*packet
) + desc
->InputLength
);
329 buffer
= (BYTE
*)(packet
+ 1);
331 report
= find_report_with_type_and_id( ext
, HidP_Input
, 0, TRUE
);
332 if (!report
) WARN("no input report found.\n");
333 else report_id
= report
->ReportID
;
337 packet
->reportId
= buffer
[0] = report_id
;
338 packet
->reportBuffer
= buffer
;
339 packet
->reportBufferLen
= desc
->InputLength
;
343 packet
->reportBuffer
++;
344 packet
->reportBufferLen
--;
347 call_minidriver( IOCTL_HID_READ_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0,
348 packet
->reportBuffer
, packet
->reportBufferLen
, &io
);
350 if (io
.Status
== STATUS_SUCCESS
)
352 if (!report_id
) io
.Information
++;
353 if (!(report
= find_report_with_type_and_id( ext
, HidP_Input
, buffer
[0], FALSE
)))
354 WARN( "dropping unknown input id %u\n", buffer
[0] );
355 else if (!polled
&& io
.Information
< report
->InputLength
)
356 WARN( "dropping short report, len %Iu expected %u\n", io
.Information
, report
->InputLength
);
359 packet
->reportId
= buffer
[0];
360 packet
->reportBuffer
= buffer
;
361 packet
->reportBufferLen
= io
.Information
;
362 hid_device_queue_input( device
, packet
);
366 res
= WaitForSingleObject(ext
->u
.pdo
.halt_event
, polled
? ext
->u
.pdo
.poll_interval
: 0);
367 } while (res
== WAIT_TIMEOUT
);
369 TRACE( "device thread exiting, res %#lx\n", res
);
373 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
375 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
376 ext
->u
.pdo
.halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
377 ext
->u
.pdo
.thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
380 struct device_strings
383 const WCHAR
*product
;
386 static const struct device_strings device_strings
[] =
388 /* Microsoft controllers */
389 { .id
= L
"VID_045E&PID_028E", .product
= L
"Controller (XBOX 360 For Windows)" },
390 { .id
= L
"VID_045E&PID_028F", .product
= L
"Controller (XBOX 360 For Windows)" },
391 { .id
= L
"VID_045E&PID_02D1", .product
= L
"Controller (Xbox One For Windows)" },
392 { .id
= L
"VID_045E&PID_02DD", .product
= L
"Controller (Xbox One For Windows)" },
393 { .id
= L
"VID_045E&PID_02E3", .product
= L
"Controller (Xbox One For Windows)" },
394 { .id
= L
"VID_045E&PID_02EA", .product
= L
"Controller (Xbox One For Windows)" },
395 { .id
= L
"VID_045E&PID_02FD", .product
= L
"Controller (Xbox One For Windows)" },
396 { .id
= L
"VID_045E&PID_0719", .product
= L
"Controller (XBOX 360 For Windows)" },
397 { .id
= L
"VID_045E&PID_0B00", .product
= L
"Controller (Xbox One For Windows)" },
398 { .id
= L
"VID_045E&PID_0B05", .product
= L
"Controller (Xbox One For Windows)" },
399 { .id
= L
"VID_045E&PID_0B12", .product
= L
"Controller (Xbox One For Windows)" },
400 { .id
= L
"VID_045E&PID_0B13", .product
= L
"Controller (Xbox One For Windows)" },
401 /* Sony controllers */
402 { .id
= L
"VID_054C&PID_05C4", .product
= L
"Wireless Controller" },
403 { .id
= L
"VID_054C&PID_09CC", .product
= L
"Wireless Controller" },
404 { .id
= L
"VID_054C&PID_0BA0", .product
= L
"Wireless Controller" },
405 { .id
= L
"VID_054C&PID_0CE6", .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 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
530 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
531 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
532 NTSTATUS status
= irp
->IoStatus
.Status
;
538 irp
->IoStatus
.Information
= 0;
540 TRACE( "device %p code %#lx\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
542 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
543 removed
= ext
->u
.pdo
.removed
;
544 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
548 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
549 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
550 return STATUS_DELETE_PENDING
;
553 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
555 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
556 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
557 status
= STATUS_BUFFER_OVERFLOW
;
560 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.poll_interval
;
561 irp
->IoStatus
.Information
= sizeof(ULONG
);
562 status
= STATUS_SUCCESS
;
565 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
568 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
569 status
= STATUS_BUFFER_TOO_SMALL
;
572 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
573 if (poll_interval
) ext
->u
.pdo
.poll_interval
= min( poll_interval
, MAX_POLL_INTERVAL_MSEC
);
574 status
= STATUS_SUCCESS
;
578 case IOCTL_HID_GET_PRODUCT_STRING
:
579 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
580 case IOCTL_HID_GET_MANUFACTURER_STRING
:
582 WCHAR
*output_buf
= MmGetSystemAddressForMdlSafe( irp
->MdlAddress
, NormalPagePriority
);
583 ULONG output_len
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
585 if (code
== IOCTL_HID_GET_PRODUCT_STRING
) index
= HID_STRING_ID_IPRODUCT
;
586 if (code
== IOCTL_HID_GET_SERIALNUMBER_STRING
) index
= HID_STRING_ID_ISERIALNUMBER
;
587 if (code
== IOCTL_HID_GET_MANUFACTURER_STRING
) index
= HID_STRING_ID_IMANUFACTURER
;
589 if ((str
= find_device_string( ext
->device_id
, index
)))
591 irp
->IoStatus
.Information
= (wcslen( str
) + 1) * sizeof(WCHAR
);
592 if (irp
->IoStatus
.Information
> output_len
)
593 status
= STATUS_BUFFER_TOO_SMALL
;
596 memcpy( output_buf
, str
, irp
->IoStatus
.Information
);
597 status
= STATUS_SUCCESS
;
602 call_minidriver( IOCTL_HID_GET_STRING
, ext
->u
.pdo
.parent_fdo
, ULongToPtr( index
),
603 sizeof(index
), output_buf
, output_len
, &irp
->IoStatus
);
604 status
= irp
->IoStatus
.Status
;
607 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
609 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
610 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
611 status
= STATUS_BUFFER_OVERFLOW
;
614 memcpy( irp
->AssociatedIrp
.SystemBuffer
, &ext
->u
.pdo
.information
,
615 sizeof(HID_COLLECTION_INFORMATION
) );
616 status
= STATUS_SUCCESS
;
620 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
622 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
624 irp
->IoStatus
.Information
= desc
->PreparsedDataLength
;
625 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< desc
->PreparsedDataLength
)
626 status
= STATUS_INVALID_BUFFER_SIZE
;
629 memcpy( irp
->UserBuffer
, desc
->PreparsedData
, desc
->PreparsedDataLength
);
630 status
= STATUS_SUCCESS
;
634 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
636 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
637 status
= STATUS_BUFFER_OVERFLOW
;
639 status
= hid_queue_resize( queue
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
642 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
644 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
645 status
= STATUS_BUFFER_TOO_SMALL
;
648 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= queue
->length
;
649 irp
->IoStatus
.Information
= sizeof(ULONG
);
650 status
= STATUS_SUCCESS
;
654 case IOCTL_HID_GET_FEATURE
:
655 case IOCTL_HID_SET_FEATURE
:
656 case IOCTL_HID_GET_INPUT_REPORT
:
657 case IOCTL_HID_SET_OUTPUT_REPORT
:
658 status
= hid_device_xfer_report( ext
, code
, irp
);
661 case IOCTL_HID_GET_WINE_RAWINPUT_HANDLE
:
662 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
663 status
= STATUS_BUFFER_OVERFLOW
;
666 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.rawinput_handle
;
667 irp
->IoStatus
.Information
= sizeof(ULONG
);
668 status
= STATUS_SUCCESS
;
674 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
675 FIXME( "Unsupported ioctl %#lx (device=%lx access=%lx func=%lx method=%lx)\n", code
,
676 code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3 );
677 status
= STATUS_NOT_SUPPORTED
;
682 if (status
!= STATUS_PENDING
)
684 irp
->IoStatus
.Status
= status
;
685 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
690 NTSTATUS WINAPI
pdo_read(DEVICE_OBJECT
*device
, IRP
*irp
)
692 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
693 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
694 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
695 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
696 struct hid_report
*report
;
700 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
701 removed
= ext
->u
.pdo
.removed
;
702 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
706 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
707 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
708 return STATUS_DELETE_PENDING
;
711 if (irpsp
->Parameters
.Read
.Length
< desc
->InputLength
)
713 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
714 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
715 return STATUS_INVALID_BUFFER_SIZE
;
718 irp
->IoStatus
.Information
= 0;
719 if ((report
= hid_queue_pop_report( queue
)))
721 memcpy( irp
->AssociatedIrp
.SystemBuffer
, report
->buffer
, report
->length
);
722 irp
->IoStatus
.Information
= report
->length
;
723 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
724 hid_report_decref( report
);
726 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
727 return STATUS_SUCCESS
;
730 return hid_queue_push_irp( queue
, irp
);
734 NTSTATUS WINAPI
pdo_write(DEVICE_OBJECT
*device
, IRP
*irp
)
736 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
737 NTSTATUS status
= hid_device_xfer_report( ext
, IOCTL_HID_WRITE_REPORT
, irp
);
738 if (status
!= STATUS_PENDING
)
740 irp
->IoStatus
.Status
= status
;
741 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
746 NTSTATUS WINAPI
pdo_create(DEVICE_OBJECT
*device
, IRP
*irp
)
748 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
749 struct hid_queue
*queue
;
753 TRACE("Open handle on device %p\n", device
);
755 KeAcquireSpinLock( &ext
->u
.pdo
.lock
, &irql
);
756 removed
= ext
->u
.pdo
.removed
;
757 KeReleaseSpinLock( &ext
->u
.pdo
.lock
, irql
);
761 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
762 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
763 return STATUS_DELETE_PENDING
;
766 if (!(queue
= hid_queue_create())) irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
769 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
770 list_add_tail( &ext
->u
.pdo
.queues
, &queue
->entry
);
771 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
773 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= queue
;
774 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
777 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
778 return STATUS_SUCCESS
;
781 NTSTATUS WINAPI
pdo_close(DEVICE_OBJECT
*device
, IRP
*irp
)
783 struct hid_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
784 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
788 TRACE("Close handle on device %p\n", device
);
790 KeAcquireSpinLock( &ext
->u
.pdo
.lock
, &irql
);
791 removed
= ext
->u
.pdo
.removed
;
792 KeReleaseSpinLock( &ext
->u
.pdo
.lock
, irql
);
796 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
797 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
798 return STATUS_DELETE_PENDING
;
803 KeAcquireSpinLock( &ext
->u
.pdo
.queues_lock
, &irql
);
804 list_remove( &queue
->entry
);
805 KeReleaseSpinLock( &ext
->u
.pdo
.queues_lock
, irql
);
806 hid_queue_destroy( queue
);
809 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
810 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
811 return STATUS_SUCCESS
;