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 IRP
*pop_irp_from_queue(BASE_DEVICE_EXTENSION
*ext
)
42 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
44 while (!irp
&& (entry
= RemoveHeadList(&ext
->u
.pdo
.irp_queue
)) != &ext
->u
.pdo
.irp_queue
)
46 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.ListEntry
);
47 if (!IoSetCancelRoutine(irp
, NULL
))
49 /* cancel routine is already cleared, meaning that it was called. let it handle completion. */
50 InitializeListHead(&irp
->Tail
.Overlay
.ListEntry
);
55 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
59 static void WINAPI
read_cancel_routine(DEVICE_OBJECT
*device
, IRP
*irp
)
61 BASE_DEVICE_EXTENSION
*ext
;
64 TRACE("cancel %p IRP on device %p\n", irp
, device
);
66 ext
= device
->DeviceExtension
;
68 IoReleaseCancelSpinLock(irp
->CancelIrql
);
70 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &old_irql
);
72 RemoveEntryList(&irp
->Tail
.Overlay
.ListEntry
);
74 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, old_irql
);
76 irp
->IoStatus
.Status
= STATUS_CANCELLED
;
77 irp
->IoStatus
.Information
= 0;
78 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
81 static struct hid_report
*hid_report_create( HID_XFER_PACKET
*packet
)
83 struct hid_report
*report
;
85 if (!(report
= malloc( offsetof( struct hid_report
, buffer
[packet
->reportBufferLen
] ) )))
88 report
->length
= packet
->reportBufferLen
;
89 memcpy( report
->buffer
, packet
->reportBuffer
, report
->length
);
94 static void hid_report_incref( struct hid_report
*report
)
96 InterlockedIncrement( &report
->ref
);
99 static void hid_report_decref( struct hid_report
*report
)
102 if (InterlockedDecrement( &report
->ref
) == 0) free( report
);
105 static struct hid_report_queue
*hid_report_queue_create( void )
107 struct hid_report_queue
*queue
;
109 if (!(queue
= calloc( 1, sizeof(struct hid_report_queue
) ))) return NULL
;
110 KeInitializeSpinLock( &queue
->lock
);
111 list_init( &queue
->entry
);
114 queue
->write_idx
= 0;
119 static void hid_report_queue_destroy( struct hid_report_queue
*queue
)
121 while (queue
->length
--) hid_report_decref( queue
->reports
[queue
->length
] );
125 static NTSTATUS
hid_report_queue_resize( struct hid_report_queue
*queue
, ULONG length
)
127 struct hid_report
*old_reports
[512];
128 LONG old_length
= queue
->length
;
131 if (length
< 2 || length
> 512) return STATUS_INVALID_PARAMETER
;
132 if (length
== queue
->length
) return STATUS_SUCCESS
;
134 KeAcquireSpinLock( &queue
->lock
, &irql
);
135 memcpy( old_reports
, queue
->reports
, old_length
* sizeof(void *) );
136 memset( queue
->reports
, 0, old_length
* sizeof(void *) );
137 queue
->length
= length
;
138 queue
->write_idx
= 0;
140 KeReleaseSpinLock( &queue
->lock
, irql
);
142 while (old_length
--) hid_report_decref( old_reports
[old_length
] );
143 return STATUS_SUCCESS
;
146 static void hid_report_queue_push( struct hid_report_queue
*queue
, struct hid_report
*report
)
148 ULONG i
= queue
->write_idx
, next
= i
+ 1;
149 struct hid_report
*prev
;
152 if (next
>= queue
->length
) next
= 0;
153 hid_report_incref( report
);
155 KeAcquireSpinLock( &queue
->lock
, &irql
);
156 prev
= queue
->reports
[i
];
157 queue
->reports
[i
] = report
;
158 if (next
!= queue
->read_idx
) queue
->write_idx
= next
;
159 KeReleaseSpinLock( &queue
->lock
, irql
);
161 hid_report_decref( prev
);
164 static struct hid_report
*hid_report_queue_pop( struct hid_report_queue
*queue
)
166 ULONG i
= queue
->read_idx
, next
= i
+ 1;
167 struct hid_report
*report
;
170 if (next
>= queue
->length
) next
= 0;
172 KeAcquireSpinLock( &queue
->lock
, &irql
);
173 report
= queue
->reports
[i
];
174 queue
->reports
[i
] = NULL
;
175 if (i
!= queue
->write_idx
) queue
->read_idx
= next
;
176 KeReleaseSpinLock( &queue
->lock
, irql
);
181 static void hid_device_queue_input( DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
)
183 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
184 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
185 const BOOL polled
= ext
->u
.pdo
.information
.Polled
;
186 struct hid_report
*last_report
, *report
;
187 struct hid_report_queue
*queue
;
193 size
= offsetof( RAWINPUT
, data
.hid
.bRawData
[packet
->reportBufferLen
] );
194 if (!(rawinput
= malloc( size
))) ERR( "Failed to allocate rawinput data!\n" );
199 rawinput
->header
.dwType
= RIM_TYPEHID
;
200 rawinput
->header
.dwSize
= size
;
201 rawinput
->header
.hDevice
= ULongToHandle( ext
->u
.pdo
.rawinput_handle
);
202 rawinput
->header
.wParam
= RIM_INPUT
;
203 rawinput
->data
.hid
.dwCount
= 1;
204 rawinput
->data
.hid
.dwSizeHid
= packet
->reportBufferLen
;
205 memcpy( rawinput
->data
.hid
.bRawData
, packet
->reportBuffer
, packet
->reportBufferLen
);
207 input
.type
= INPUT_HARDWARE
;
208 input
.hi
.uMsg
= WM_INPUT
;
209 input
.hi
.wParamH
= 0;
210 input
.hi
.wParamL
= 0;
211 __wine_send_input( 0, &input
, rawinput
);
216 if (!(last_report
= hid_report_create( packet
)))
218 ERR( "Failed to allocate hid_report!\n" );
222 KeAcquireSpinLock( &ext
->u
.pdo
.report_queues_lock
, &irql
);
223 LIST_FOR_EACH_ENTRY( queue
, &ext
->u
.pdo
.report_queues
, struct hid_report_queue
, entry
)
224 hid_report_queue_push( queue
, last_report
);
225 KeReleaseSpinLock( &ext
->u
.pdo
.report_queues_lock
, irql
);
229 if (!(irp
= pop_irp_from_queue( ext
))) break;
230 queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
232 if (!(report
= hid_report_queue_pop( queue
))) hid_report_incref( (report
= last_report
) );
233 memcpy( irp
->AssociatedIrp
.SystemBuffer
, report
->buffer
, desc
->InputLength
);
234 irp
->IoStatus
.Information
= report
->length
;
235 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
236 hid_report_decref( report
);
238 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
242 hid_report_decref( last_report
);
245 static DWORD CALLBACK
hid_device_thread(void *args
)
247 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
248 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
249 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
250 HIDP_REPORT_IDS
*reports
= ext
->u
.pdo
.device_desc
.ReportIDs
;
251 ULONG report_count
= ext
->u
.pdo
.device_desc
.ReportIDsLength
;
252 BOOL polled
= ext
->u
.pdo
.information
.Polled
;
253 ULONG i
, report_id
= 0, timeout
= 0;
254 HID_XFER_PACKET
*packet
;
259 packet
= malloc( sizeof(*packet
) + desc
->InputLength
);
260 buffer
= (BYTE
*)(packet
+ 1);
261 packet
->reportBuffer
= buffer
;
263 if (polled
) timeout
= ext
->u
.pdo
.poll_interval
;
265 for (i
= 0; i
< report_count
; ++i
)
267 if (!reports
[i
].ReportID
|| reports
[i
].InputLength
)
271 if (i
== report_count
) WARN("no input report found.\n");
272 else report_id
= reports
[i
].ReportID
;
276 packet
->reportId
= buffer
[0] = report_id
;
277 packet
->reportBufferLen
= desc
->InputLength
;
281 packet
->reportBuffer
++;
282 packet
->reportBufferLen
--;
285 call_minidriver( IOCTL_HID_READ_REPORT
, ext
->u
.pdo
.parent_fdo
, NULL
, 0,
286 packet
->reportBuffer
, packet
->reportBufferLen
, &io
);
288 if (io
.Status
== STATUS_SUCCESS
)
290 if (!report_id
) io
.Information
++;
291 packet
->reportId
= buffer
[0];
292 packet
->reportBuffer
= buffer
;
293 packet
->reportBufferLen
= io
.Information
;
295 if (polled
|| io
.Information
== desc
->InputLength
)
296 hid_device_queue_input( device
, packet
);
299 res
= WaitForSingleObject(ext
->u
.pdo
.halt_event
, timeout
);
300 } while (res
== WAIT_TIMEOUT
);
302 TRACE("device thread exiting, res %#x\n", res
);
306 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
308 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
309 ext
->u
.pdo
.halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
310 ext
->u
.pdo
.thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
313 static void handle_IOCTL_HID_GET_COLLECTION_INFORMATION( IRP
*irp
, BASE_DEVICE_EXTENSION
*ext
)
315 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
316 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
318 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
319 irp
->IoStatus
.Information
= 0;
323 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &ext
->u
.pdo
.information
, sizeof(HID_COLLECTION_INFORMATION
));
324 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
325 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
329 static void handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( IRP
*irp
, BASE_DEVICE_EXTENSION
*ext
)
331 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
332 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
334 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< desc
->PreparsedDataLength
)
336 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
337 irp
->IoStatus
.Information
= 0;
341 memcpy( irp
->UserBuffer
, desc
->PreparsedData
, desc
->PreparsedDataLength
);
342 irp
->IoStatus
.Information
= desc
->PreparsedDataLength
;
343 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
347 static void handle_minidriver_string( BASE_DEVICE_EXTENSION
*ext
, IRP
*irp
, SHORT index
)
349 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
353 InputBuffer
= MAKELONG(index
, 0);
355 call_minidriver( IOCTL_HID_GET_STRING
, ext
->u
.pdo
.parent_fdo
, ULongToPtr( InputBuffer
),
356 sizeof(InputBuffer
), buffer
, sizeof(buffer
), &irp
->IoStatus
);
358 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
360 WCHAR
*out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
361 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
362 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
363 lstrcpynW(out_buffer
, buffer
, length
);
364 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
368 static void hid_device_xfer_report( BASE_DEVICE_EXTENSION
*ext
, ULONG code
, IRP
*irp
)
370 HIDP_REPORT_IDS
*reports
= ext
->u
.pdo
.device_desc
.ReportIDs
;
371 ULONG report_count
= ext
->u
.pdo
.device_desc
.ReportIDsLength
;
372 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation( irp
);
373 ULONG i
, offset
= 0, report_len
= 0, buffer_len
= 0;
374 HID_XFER_PACKET packet
;
379 case IOCTL_HID_GET_FEATURE
:
380 case IOCTL_HID_GET_INPUT_REPORT
:
381 buffer_len
= stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
382 buffer
= MmGetSystemAddressForMdlSafe( irp
->MdlAddress
, NormalPagePriority
);
384 case IOCTL_HID_SET_FEATURE
:
385 case IOCTL_HID_SET_OUTPUT_REPORT
:
386 buffer_len
= stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
387 buffer
= irp
->AssociatedIrp
.SystemBuffer
;
389 case IOCTL_HID_WRITE_REPORT
:
390 buffer_len
= stack
->Parameters
.Write
.Length
;
391 buffer
= irp
->AssociatedIrp
.SystemBuffer
;
394 if (!buffer
|| !buffer_len
)
396 irp
->IoStatus
.Status
= STATUS_INVALID_USER_BUFFER
;
400 for (i
= 0; i
< report_count
; ++i
)
402 if (!reports
[i
].ReportID
|| reports
[i
].ReportID
== buffer
[0])
405 if (i
== report_count
)
407 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
410 if (!reports
[i
].ReportID
) offset
= 1;
414 case IOCTL_HID_GET_INPUT_REPORT
:
415 report_len
= reports
[i
].InputLength
;
417 case IOCTL_HID_SET_OUTPUT_REPORT
:
418 case IOCTL_HID_WRITE_REPORT
:
419 report_len
= reports
[i
].OutputLength
;
421 case IOCTL_HID_GET_FEATURE
:
422 case IOCTL_HID_SET_FEATURE
:
423 report_len
= reports
[i
].FeatureLength
;
426 if (buffer_len
< report_len
)
428 irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
432 packet
.reportId
= reports
[i
].ReportID
;
433 packet
.reportBuffer
= buffer
+ offset
;
437 case IOCTL_HID_GET_FEATURE
:
438 case IOCTL_HID_GET_INPUT_REPORT
:
439 packet
.reportBufferLen
= buffer_len
- offset
;
440 call_minidriver( code
, ext
->u
.pdo
.parent_fdo
, NULL
, 0, &packet
, sizeof(packet
), &irp
->IoStatus
);
442 case IOCTL_HID_SET_FEATURE
:
443 case IOCTL_HID_SET_OUTPUT_REPORT
:
444 case IOCTL_HID_WRITE_REPORT
:
445 packet
.reportBufferLen
= report_len
- offset
;
446 call_minidriver( code
, ext
->u
.pdo
.parent_fdo
, NULL
, sizeof(packet
), &packet
, 0, &irp
->IoStatus
);
447 if (code
== IOCTL_HID_WRITE_REPORT
&& packet
.reportId
) irp
->IoStatus
.Information
--;
452 NTSTATUS WINAPI
pdo_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
454 struct hid_report_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
455 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
456 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
462 irp
->IoStatus
.Information
= 0;
464 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
466 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
467 removed
= ext
->u
.pdo
.removed
;
468 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
472 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
473 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
474 return STATUS_DELETE_PENDING
;
477 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
479 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
480 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
481 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
483 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
484 irp
->IoStatus
.Information
= 0;
487 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= ext
->u
.pdo
.poll_interval
;
488 irp
->IoStatus
.Information
= sizeof(ULONG
);
489 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
491 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
494 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
495 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
497 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
500 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
501 if (poll_interval
) ext
->u
.pdo
.poll_interval
= min(poll_interval
, MAX_POLL_INTERVAL_MSEC
);
502 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
505 case IOCTL_HID_GET_PRODUCT_STRING
:
507 handle_minidriver_string( ext
, irp
, HID_STRING_ID_IPRODUCT
);
510 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
512 handle_minidriver_string( ext
, irp
, HID_STRING_ID_ISERIALNUMBER
);
515 case IOCTL_HID_GET_MANUFACTURER_STRING
:
517 handle_minidriver_string( ext
, irp
, HID_STRING_ID_IMANUFACTURER
);
520 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
522 handle_IOCTL_HID_GET_COLLECTION_INFORMATION( irp
, ext
);
525 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
527 handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( irp
, ext
);
530 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
532 irp
->IoStatus
.Information
= 0;
534 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
535 irp
->IoStatus
.Status
= STATUS_BUFFER_OVERFLOW
;
537 irp
->IoStatus
.Status
= hid_report_queue_resize( queue
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
540 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
542 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
544 irp
->IoStatus
.Information
= 0;
545 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
549 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= queue
->length
;
550 irp
->IoStatus
.Information
= sizeof(ULONG
);
551 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
555 case IOCTL_HID_GET_FEATURE
:
556 case IOCTL_HID_SET_FEATURE
:
557 case IOCTL_HID_GET_INPUT_REPORT
:
558 case IOCTL_HID_SET_OUTPUT_REPORT
:
559 hid_device_xfer_report( ext
, code
, irp
);
563 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
564 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
565 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
566 irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
571 status
= irp
->IoStatus
.Status
;
572 if (status
!= STATUS_PENDING
) IoCompleteRequest( irp
, IO_NO_INCREMENT
);
576 NTSTATUS WINAPI
pdo_read(DEVICE_OBJECT
*device
, IRP
*irp
)
578 struct hid_report_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
579 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
580 HIDP_COLLECTION_DESC
*desc
= ext
->u
.pdo
.device_desc
.CollectionDesc
;
581 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
582 struct hid_report
*report
;
587 KeAcquireSpinLock(&ext
->u
.pdo
.lock
, &irql
);
588 removed
= ext
->u
.pdo
.removed
;
589 KeReleaseSpinLock(&ext
->u
.pdo
.lock
, irql
);
593 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
594 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
595 return STATUS_DELETE_PENDING
;
598 if (irpsp
->Parameters
.Read
.Length
< desc
->InputLength
)
600 irp
->IoStatus
.Status
= STATUS_INVALID_BUFFER_SIZE
;
601 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
602 return STATUS_INVALID_BUFFER_SIZE
;
605 irp
->IoStatus
.Information
= 0;
606 if ((report
= hid_report_queue_pop( queue
)))
608 memcpy( irp
->AssociatedIrp
.SystemBuffer
, report
->buffer
, desc
->InputLength
);
609 irp
->IoStatus
.Information
= report
->length
;
610 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
611 hid_report_decref( report
);
615 KeAcquireSpinLock(&ext
->u
.pdo
.irp_queue_lock
, &irql
);
617 IoSetCancelRoutine(irp
, read_cancel_routine
);
618 if (irp
->Cancel
&& !IoSetCancelRoutine(irp
, NULL
))
620 /* IRP was canceled before we set cancel routine */
621 InitializeListHead(&irp
->Tail
.Overlay
.ListEntry
);
622 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, irql
);
623 return STATUS_CANCELLED
;
626 InsertTailList(&ext
->u
.pdo
.irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
627 irp
->IoStatus
.Status
= STATUS_PENDING
;
628 IoMarkIrpPending(irp
);
630 KeReleaseSpinLock(&ext
->u
.pdo
.irp_queue_lock
, irql
);
633 status
= irp
->IoStatus
.Status
;
634 if (status
!= STATUS_PENDING
) IoCompleteRequest( irp
, IO_NO_INCREMENT
);
638 NTSTATUS WINAPI
pdo_write(DEVICE_OBJECT
*device
, IRP
*irp
)
640 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
643 hid_device_xfer_report( ext
, IOCTL_HID_WRITE_REPORT
, irp
);
645 status
= irp
->IoStatus
.Status
;
646 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
650 NTSTATUS WINAPI
pdo_create(DEVICE_OBJECT
*device
, IRP
*irp
)
652 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
653 struct hid_report_queue
*queue
;
656 TRACE("Open handle on device %p\n", device
);
658 if (!(queue
= hid_report_queue_create())) irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
661 KeAcquireSpinLock( &ext
->u
.pdo
.report_queues_lock
, &irql
);
662 list_add_tail( &ext
->u
.pdo
.report_queues
, &queue
->entry
);
663 KeReleaseSpinLock( &ext
->u
.pdo
.report_queues_lock
, irql
);
665 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= queue
;
666 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
669 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
670 return STATUS_SUCCESS
;
673 NTSTATUS WINAPI
pdo_close(DEVICE_OBJECT
*device
, IRP
*irp
)
675 struct hid_report_queue
*queue
= irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
;
676 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
679 TRACE("Close handle on device %p\n", device
);
683 KeAcquireSpinLock( &ext
->u
.pdo
.report_queues_lock
, &irql
);
684 list_remove( &queue
->entry
);
685 KeReleaseSpinLock( &ext
->u
.pdo
.report_queues_lock
, irql
);
686 hid_report_queue_destroy( queue
);
689 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
690 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
691 return STATUS_SUCCESS
;