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
24 #define NONAMELESSUNION
26 #include "wine/unicode.h"
31 #include "wine/debug.h"
32 #include "ddk/hidsdi.h"
33 #include "ddk/hidtypes.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
39 WINE_DECLARE_DEBUG_CHANNEL(hid_report
);
41 static const WCHAR device_name_fmtW
[] = {'\\','D','e','v','i','c','e',
42 '\\','H','I','D','#','%','p','&','%','p',0};
43 static const WCHAR device_regname_fmtW
[] = {'H','I','D','\\',
44 'v','i','d','_','%','0','4','x','&','p','i','d','_','%',
45 '0','4','x','&','%','s','\\','%','i','&','%','s',0};
46 static const WCHAR device_link_fmtW
[] = {'\\','?','?','\\','h','i','d','#',
47 'v','i','d','_','%','0','4','x','&','p','i','d','_','%',
48 '0','4','x','&','%','s','#','%','i','&','%','s','#','%','s',0};
49 /* GUID_DEVINTERFACE_HID */
50 static const WCHAR class_guid
[] = {'{','4','D','1','E','5','5','B','2',
51 '-','F','1','6','F','-','1','1','C','F','-','8','8','C','B','-','0','0',
52 '1','1','1','1','0','0','0','0','3','0','}',0};
55 NTSTATUS
HID_CreateDevice(DEVICE_OBJECT
*native_device
, HID_MINIDRIVER_REGISTRATION
*driver
, DEVICE_OBJECT
**device
)
60 BASE_DEVICE_EXTENSION
*ext
;
62 sprintfW(dev_name
, device_name_fmtW
, driver
->DriverObject
, native_device
);
63 RtlInitUnicodeString( &nameW
, dev_name
);
65 TRACE("Create base hid device %s\n", debugstr_w(dev_name
));
67 status
= IoCreateDevice(driver
->DriverObject
, driver
->DeviceExtensionSize
+ sizeof(BASE_DEVICE_EXTENSION
), &nameW
, 0, 0, FALSE
, device
);
70 FIXME( "failed to create device error %x\n", status
);
74 ext
= (*device
)->DeviceExtension
;
76 ext
->deviceExtension
.MiniDeviceExtension
= ext
+ 1;
77 ext
->deviceExtension
.PhysicalDeviceObject
= *device
;
78 ext
->deviceExtension
.NextDeviceObject
= native_device
;
79 ext
->device_name
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(dev_name
) + 1) * sizeof(WCHAR
));
80 lstrcpyW(ext
->device_name
, dev_name
);
81 ext
->link_name
= NULL
;
86 NTSTATUS
HID_LinkDevice(DEVICE_OBJECT
*device
, LPCWSTR serial
, LPCWSTR index
)
91 UNICODE_STRING nameW
, linkW
;
95 BASE_DEVICE_EXTENSION
*ext
;
97 HidD_GetHidGuid(&hidGuid
);
98 ext
= device
->DeviceExtension
;
100 sprintfW(dev_link
, device_link_fmtW
, ext
->information
.VendorID
,
101 ext
->information
.ProductID
, index
, ext
->information
.VersionNumber
, serial
,
105 RtlInitUnicodeString( &nameW
, ext
->device_name
);
106 RtlInitUnicodeString( &linkW
, dev_link
);
108 TRACE("Create link %s\n", debugstr_w(dev_link
));
110 ext
->link_name
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
) * (lstrlenW(dev_link
) + 1));
111 lstrcpyW(ext
->link_name
, dev_link
);
113 status
= IoCreateSymbolicLink( &linkW
, &nameW
);
116 FIXME( "failed to create link error %x\n", status
);
120 sprintfW(regname
, device_regname_fmtW
, ext
->information
.VendorID
, ext
->information
.ProductID
, index
, ext
->information
.VersionNumber
, serial
);
122 devinfo
= SetupDiGetClassDevsW(&GUID_DEVCLASS_HIDCLASS
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
125 FIXME( "failed to get ClassDevs %x\n", GetLastError());
126 return GetLastError();
128 Data
.cbSize
= sizeof(Data
);
129 if (!SetupDiCreateDeviceInfoW(devinfo
, regname
, &GUID_DEVCLASS_HIDCLASS
, NULL
, NULL
, DICD_INHERIT_CLASSDRVS
, &Data
))
131 if (GetLastError() == ERROR_DEVINST_ALREADY_EXISTS
)
133 SetupDiDestroyDeviceInfoList(devinfo
);
134 return ERROR_SUCCESS
;
136 FIXME( "failed to Create Device Info %x\n", GetLastError());
137 return GetLastError();
139 if (!SetupDiRegisterDeviceInfo( devinfo
, &Data
, 0, NULL
, NULL
, NULL
))
141 FIXME( "failed to Register Device Info %x\n", GetLastError());
142 return GetLastError();
144 if (!SetupDiCreateDeviceInterfaceW( devinfo
, &Data
, &hidGuid
, NULL
, 0, NULL
))
146 FIXME( "failed to Create Device Interface %x\n", GetLastError());
147 return GetLastError();
149 SetupDiDestroyDeviceInfoList(devinfo
);
154 void HID_DeleteDevice(HID_MINIDRIVER_REGISTRATION
*driver
, DEVICE_OBJECT
*device
)
157 BASE_DEVICE_EXTENSION
*ext
;
158 UNICODE_STRING linkW
;
162 ext
= device
->DeviceExtension
;
166 TRACE("Delete link %s\n", debugstr_w(ext
->link_name
));
167 RtlInitUnicodeString(&linkW
, ext
->link_name
);
169 status
= IoDeleteSymbolicLink(&linkW
);
170 if (status
!= STATUS_SUCCESS
)
171 ERR("Delete Symbolic Link failed (%x)\n",status
);
176 SetEvent(ext
->halt_event
);
177 WaitForSingleObject(ext
->thread
, INFINITE
);
179 CloseHandle(ext
->halt_event
);
181 HeapFree(GetProcessHeap(), 0, ext
->preparseData
);
182 if (ext
->ring_buffer
)
183 RingBuffer_Destroy(ext
->ring_buffer
);
185 entry
= RemoveHeadList(&ext
->irp_queue
);
186 while(entry
!= &ext
->irp_queue
)
188 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.ListEntry
);
189 irp
->IoStatus
.u
.Status
= STATUS_DEVICE_REMOVED
;
190 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
191 entry
= RemoveHeadList(&ext
->irp_queue
);
194 TRACE("Delete device(%p) %s\n", device
, debugstr_w(ext
->device_name
));
195 HeapFree(GetProcessHeap(), 0, ext
->device_name
);
196 HeapFree(GetProcessHeap(), 0, ext
->link_name
);
198 IoDeleteDevice(device
);
201 static void HID_Device_processQueue(DEVICE_OBJECT
*device
)
205 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
206 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
207 HID_XFER_PACKET
*packet
;
209 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
211 entry
= RemoveHeadList(&ext
->irp_queue
);
212 while(entry
!= &ext
->irp_queue
)
215 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.ListEntry
);
216 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
218 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
221 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
222 TRACE_(hid_report
)("Processing Request (%i)\n",ptr
);
223 if (irpsp
->Parameters
.Read
.Length
>= packet
->reportBufferLen
)
225 memcpy(irp
->AssociatedIrp
.SystemBuffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
226 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
227 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
231 irp
->IoStatus
.Information
= 0;
232 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
237 irp
->IoStatus
.Information
= 0;
238 irp
->IoStatus
.u
.Status
= STATUS_UNSUCCESSFUL
;
240 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
241 entry
= RemoveHeadList(&ext
->irp_queue
);
243 HeapFree(GetProcessHeap(), 0, packet
);
246 static NTSTATUS WINAPI
read_Completion(DEVICE_OBJECT
*deviceObject
, IRP
*irp
, void *context
)
248 SetEvent(irp
->UserEvent
);
249 return STATUS_MORE_PROCESSING_REQUIRED
;
252 static DWORD CALLBACK
hid_device_thread(void *args
)
254 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
257 IO_STATUS_BLOCK irp_status
;
258 IO_STACK_LOCATION
*irpsp
;
263 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
264 events
[0] = CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
265 events
[1] = ext
->halt_event
;
267 if (ext
->information
.Polled
)
271 HID_XFER_PACKET
*packet
;
272 ResetEvent(events
[0]);
274 packet
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*packet
) + ext
->preparseData
->caps
.InputReportByteLength
);
275 packet
->reportBufferLen
= ext
->preparseData
->caps
.InputReportByteLength
;
276 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
277 packet
->reportId
= 0;
279 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_GET_INPUT_REPORT
,
280 device
, NULL
, 0, packet
, sizeof(packet
), TRUE
, events
[0],
283 irpsp
= IoGetNextIrpStackLocation(irp
);
284 irpsp
->CompletionRoutine
= read_Completion
;
285 irpsp
->Control
= SL_INVOKE_ON_SUCCESS
| SL_INVOKE_ON_ERROR
;
287 ntrc
= IoCallDriver(device
, irp
);
289 if (ntrc
== STATUS_PENDING
)
290 rc
= WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
292 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
294 RingBuffer_Write(ext
->ring_buffer
, packet
);
295 HID_Device_processQueue(device
);
298 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
300 rc
= WaitForSingleObject(ext
->halt_event
, ext
->poll_interval
);
302 if (rc
== WAIT_OBJECT_0
)
304 else if (rc
!= WAIT_TIMEOUT
)
305 ERR("Wait returned unexpected value %x\n",rc
);
310 INT exit_now
= FALSE
;
312 HID_XFER_PACKET
*packet
;
313 packet
= HeapAlloc(GetProcessHeap(), 0, sizeof(*packet
) + ext
->preparseData
->caps
.InputReportByteLength
);
314 packet
->reportBufferLen
= ext
->preparseData
->caps
.InputReportByteLength
;
315 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
316 packet
->reportId
= 0;
322 buffer
= HeapAlloc(GetProcessHeap(), 0, ext
->preparseData
->caps
.InputReportByteLength
);
324 ResetEvent(events
[0]);
326 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT
,
327 device
, NULL
, 0, buffer
,
328 ext
->preparseData
->caps
.InputReportByteLength
, TRUE
, events
[0],
331 irpsp
= IoGetNextIrpStackLocation(irp
);
332 irpsp
->CompletionRoutine
= read_Completion
;
333 irpsp
->Control
= SL_INVOKE_ON_SUCCESS
| SL_INVOKE_ON_ERROR
;
335 ntrc
= IoCallDriver(device
, irp
);
337 if (ntrc
== STATUS_PENDING
)
339 rc
= WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
341 if (rc
== WAIT_OBJECT_0
+ 1)
345 if (!exit_now
&& irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
347 packet
->reportId
= buffer
[0];
348 memcpy(packet
->reportBuffer
, buffer
, ext
->preparseData
->caps
.InputReportByteLength
);
349 RingBuffer_Write(ext
->ring_buffer
, packet
);
350 HID_Device_processQueue(device
);
353 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
359 HeapFree(GetProcessHeap(), 0, packet
);
362 CloseHandle(events
[0]);
364 TRACE("Device thread exiting\n");
368 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
370 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
371 ext
->halt_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
372 ext
->thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
375 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
377 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
378 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
380 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
381 irp
->IoStatus
.Information
= 0;
385 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &base
->information
, sizeof(HID_COLLECTION_INFORMATION
));
386 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
387 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
389 return STATUS_SUCCESS
;
392 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
394 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
396 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< base
->preparseData
->dwSize
)
398 irp
->IoStatus
.u
.Status
= STATUS_INVALID_BUFFER_SIZE
;
399 irp
->IoStatus
.Information
= 0;
403 memcpy(irp
->UserBuffer
, base
->preparseData
, base
->preparseData
->dwSize
);
404 irp
->IoStatus
.Information
= base
->preparseData
->dwSize
;
405 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
407 return STATUS_SUCCESS
;
410 static NTSTATUS
handle_minidriver_string(DEVICE_OBJECT
*device
, IRP
*irp
, SHORT index
)
412 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
417 InputBuffer
= MAKELONG(index
, 0);
418 status
= call_minidriver(IOCTL_HID_GET_STRING
, device
, ULongToPtr(InputBuffer
), sizeof(InputBuffer
), buffer
, sizeof(buffer
));
420 if (status
== STATUS_SUCCESS
)
422 WCHAR
*out_buffer
= (WCHAR
*)(((BYTE
*)irp
->MdlAddress
->StartVa
) + irp
->MdlAddress
->ByteOffset
);
423 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
424 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
425 lstrcpynW(out_buffer
, buffer
, length
);
426 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
428 irp
->IoStatus
.u
.Status
= status
;
430 return STATUS_SUCCESS
;
433 NTSTATUS WINAPI
HID_Device_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
435 NTSTATUS rc
= STATUS_SUCCESS
;
436 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
437 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
439 irp
->IoStatus
.Information
= 0;
441 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
443 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
445 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
446 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
447 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
449 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
450 irp
->IoStatus
.Information
= 0;
453 *((ULONG
*)irp
->AssociatedIrp
.SystemBuffer
) = extension
->poll_interval
;
454 irp
->IoStatus
.Information
= sizeof(ULONG
);
455 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
457 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
460 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
461 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
463 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_TOO_SMALL
;
466 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
467 if (poll_interval
== 0)
468 FIXME("Handle opportunistic reads\n");
469 else if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
471 extension
->poll_interval
= poll_interval
;
472 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
475 irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
478 case IOCTL_HID_GET_PRODUCT_STRING
:
480 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IPRODUCT
);
483 case IOCTL_HID_GET_MANUFACTURER_STRING
:
485 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IMANUFACTURER
);
488 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
490 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, extension
);
493 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
495 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, extension
);
498 case IOCTL_HID_GET_INPUT_REPORT
:
500 HID_XFER_PACKET packet
;
501 BYTE
* buffer
= ((BYTE
*)irp
->MdlAddress
->StartVa
) + irp
->MdlAddress
->ByteOffset
;
503 if (extension
->preparseData
->InputReports
[0].reportID
)
504 packet
.reportId
= buffer
[0];
507 packet
.reportBuffer
= buffer
;
508 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
510 call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
511 irp
->IoStatus
.Information
= packet
.reportBufferLen
;
512 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
517 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
518 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
519 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
520 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
521 rc
= STATUS_UNSUCCESSFUL
;
526 if (rc
!= STATUS_PENDING
)
527 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
532 NTSTATUS WINAPI
HID_Device_read(DEVICE_OBJECT
*device
, IRP
*irp
)
534 HID_XFER_PACKET
*packet
;
535 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
536 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
537 NTSTATUS rc
= STATUS_SUCCESS
;
540 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
541 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
543 irp
->IoStatus
.Information
= 0;
544 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
548 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
549 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
550 if (irpsp
->Parameters
.Read
.Length
>= packet
->reportBufferLen
)
552 memcpy(irp
->AssociatedIrp
.SystemBuffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
553 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
554 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
558 irp
->IoStatus
.Information
= 0;
559 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
561 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
565 TRACE_(hid_report
)("Queue irp\n");
566 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
569 HeapFree(GetProcessHeap(), 0, packet
);
574 NTSTATUS WINAPI
HID_Device_write(DEVICE_OBJECT
*device
, IRP
*irp
)
576 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
578 irp
->IoStatus
.Information
= 0;
580 TRACE("Buffer length %i\n", irpsp
->Parameters
.Write
.Length
);
582 FIXME("device %p\n", device
);
584 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
585 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
586 return STATUS_SUCCESS
;
589 NTSTATUS WINAPI
HID_Device_create(DEVICE_OBJECT
*device
, IRP
*irp
)
591 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
593 TRACE("Open handle on device %p\n", device
);
594 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->ring_buffer
));
595 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
596 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
597 return STATUS_SUCCESS
;
600 NTSTATUS WINAPI
HID_Device_close(DEVICE_OBJECT
*device
, IRP
*irp
)
602 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
603 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
604 TRACE("Close handle on device %p\n", device
);
605 RingBuffer_RemovePointer(ext
->ring_buffer
, ptr
);
606 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
607 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
608 return STATUS_SUCCESS
;