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
25 #define NONAMELESSSTRUCT
27 #include "wine/unicode.h"
32 #include "wine/debug.h"
33 #include "ddk/hidsdi.h"
34 #include "ddk/hidtypes.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
41 WINE_DECLARE_DEBUG_CHANNEL(hid_report
);
43 static const WCHAR device_name_fmtW
[] = {'\\','D','e','v','i','c','e',
44 '\\','H','I','D','#','%','p','&','%','p',0};
46 NTSTATUS
HID_CreateDevice(DEVICE_OBJECT
*native_device
, HID_MINIDRIVER_REGISTRATION
*driver
, DEVICE_OBJECT
**device
)
51 BASE_DEVICE_EXTENSION
*ext
;
53 sprintfW(dev_name
, device_name_fmtW
, driver
->DriverObject
, native_device
);
54 RtlInitUnicodeString( &nameW
, dev_name
);
56 TRACE("Create base hid device %s\n", debugstr_w(dev_name
));
58 status
= IoCreateDevice(driver
->DriverObject
, driver
->DeviceExtensionSize
+ sizeof(BASE_DEVICE_EXTENSION
), &nameW
, 0, 0, FALSE
, device
);
61 FIXME( "failed to create device error %x\n", status
);
65 ext
= (*device
)->DeviceExtension
;
67 ext
->deviceExtension
.MiniDeviceExtension
= ext
+ 1;
68 ext
->deviceExtension
.PhysicalDeviceObject
= *device
;
69 ext
->deviceExtension
.NextDeviceObject
= native_device
;
70 ext
->device_name
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(dev_name
) + 1) * sizeof(WCHAR
));
71 lstrcpyW(ext
->device_name
, dev_name
);
72 ext
->link_name
.Buffer
= NULL
;
74 IoAttachDeviceToDeviceStack(*device
, native_device
);
76 return STATUS_SUCCESS
;
79 NTSTATUS
HID_LinkDevice(DEVICE_OBJECT
*device
)
86 BASE_DEVICE_EXTENSION
*ext
;
88 HidD_GetHidGuid(&hidGuid
);
89 ext
= device
->DeviceExtension
;
91 RtlInitUnicodeString( &nameW
, ext
->device_name
);
93 devinfo
= SetupDiGetClassDevsW(&GUID_DEVCLASS_HIDCLASS
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
96 FIXME( "failed to get ClassDevs %x\n", GetLastError());
97 return STATUS_UNSUCCESSFUL
;
99 Data
.cbSize
= sizeof(Data
);
100 if (!SetupDiCreateDeviceInfoW(devinfo
, ext
->instance_id
, &GUID_DEVCLASS_HIDCLASS
, NULL
, NULL
, DICD_INHERIT_CLASSDRVS
, &Data
))
102 if (GetLastError() == ERROR_DEVINST_ALREADY_EXISTS
)
104 SetupDiDestroyDeviceInfoList(devinfo
);
105 return STATUS_SUCCESS
;
107 FIXME( "failed to Create Device Info %x\n", GetLastError());
110 if (!SetupDiRegisterDeviceInfo( devinfo
, &Data
, 0, NULL
, NULL
, NULL
))
112 FIXME( "failed to Register Device Info %x\n", GetLastError());
115 SetupDiDestroyDeviceInfoList(devinfo
);
117 status
= IoRegisterDeviceInterface(device
, &hidGuid
, NULL
, &ext
->link_name
);
118 if (status
!= STATUS_SUCCESS
)
120 FIXME( "failed to register device interface %x\n", status
);
124 return STATUS_SUCCESS
;
127 SetupDiDestroyDeviceInfoList(devinfo
);
128 return STATUS_UNSUCCESSFUL
;
131 void HID_DeleteDevice(HID_MINIDRIVER_REGISTRATION
*driver
, DEVICE_OBJECT
*device
)
133 BASE_DEVICE_EXTENSION
*ext
;
137 ext
= device
->DeviceExtension
;
141 SetEvent(ext
->halt_event
);
142 WaitForSingleObject(ext
->thread
, INFINITE
);
144 CloseHandle(ext
->halt_event
);
146 HeapFree(GetProcessHeap(), 0, ext
->preparseData
);
147 if (ext
->ring_buffer
)
148 RingBuffer_Destroy(ext
->ring_buffer
);
150 entry
= RemoveHeadList(&ext
->irp_queue
);
151 while(entry
!= &ext
->irp_queue
)
153 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
154 irp
->IoStatus
.u
.Status
= STATUS_DEVICE_REMOVED
;
155 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
156 entry
= RemoveHeadList(&ext
->irp_queue
);
159 TRACE("Delete device(%p) %s\n", device
, debugstr_w(ext
->device_name
));
160 HeapFree(GetProcessHeap(), 0, ext
->device_name
);
161 RtlFreeUnicodeString(&ext
->link_name
);
163 IoDeleteDevice(device
);
166 static NTSTATUS
copy_packet_into_buffer(HID_XFER_PACKET
*packet
, BYTE
* buffer
, ULONG buffer_length
, ULONG
*out_length
)
168 BOOL zero_id
= (packet
->reportId
== 0);
172 if ((zero_id
&& buffer_length
> packet
->reportBufferLen
) ||
173 (!zero_id
&& buffer_length
>= packet
->reportBufferLen
))
175 if (packet
->reportId
!= 0)
177 memcpy(buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
178 *out_length
= packet
->reportBufferLen
;
183 memcpy(&buffer
[1], packet
->reportBuffer
, packet
->reportBufferLen
);
184 *out_length
= packet
->reportBufferLen
+ 1;
186 return STATUS_SUCCESS
;
189 return STATUS_BUFFER_OVERFLOW
;
192 static void HID_Device_processQueue(DEVICE_OBJECT
*device
)
196 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
197 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
198 HID_XFER_PACKET
*packet
;
200 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
202 entry
= RemoveHeadList(&ext
->irp_queue
);
203 while(entry
!= &ext
->irp_queue
)
206 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
207 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
209 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
214 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
215 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
216 TRACE_(hid_report
)("Processing Request (%i)\n",ptr
);
217 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
218 irp
->IoStatus
.u
.Status
= rc
;
219 irp
->IoStatus
.Information
= out_length
;
223 irp
->IoStatus
.Information
= 0;
224 irp
->IoStatus
.u
.Status
= STATUS_UNSUCCESSFUL
;
226 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
227 entry
= RemoveHeadList(&ext
->irp_queue
);
229 HeapFree(GetProcessHeap(), 0, packet
);
232 static NTSTATUS WINAPI
read_Completion(DEVICE_OBJECT
*deviceObject
, IRP
*irp
, void *context
)
234 HANDLE event
= context
;
236 return STATUS_MORE_PROCESSING_REQUIRED
;
239 static DWORD CALLBACK
hid_device_thread(void *args
)
241 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
244 IO_STATUS_BLOCK irp_status
;
245 HID_XFER_PACKET
*packet
;
250 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
251 events
[0] = CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
252 events
[1] = ext
->halt_event
;
254 packet
= HeapAlloc(GetProcessHeap(), 0, sizeof(*packet
) + ext
->preparseData
->caps
.InputReportByteLength
);
255 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
257 if (ext
->information
.Polled
)
261 ResetEvent(events
[0]);
263 packet
->reportBufferLen
= ext
->preparseData
->caps
.InputReportByteLength
;
264 packet
->reportId
= 0;
266 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_GET_INPUT_REPORT
,
267 device
, NULL
, 0, packet
, sizeof(*packet
), TRUE
, NULL
,
270 IoSetCompletionRoutine(irp
, read_Completion
, events
[0], TRUE
, TRUE
, TRUE
);
271 ntrc
= IoCallDriver(device
, irp
);
273 if (ntrc
== STATUS_PENDING
)
274 WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
276 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
278 RingBuffer_Write(ext
->ring_buffer
, packet
);
279 HID_Device_processQueue(device
);
282 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
284 rc
= WaitForSingleObject(ext
->halt_event
, ext
->poll_interval
? ext
->poll_interval
: DEFAULT_POLL_INTERVAL
);
286 if (rc
== WAIT_OBJECT_0
)
288 else if (rc
!= WAIT_TIMEOUT
)
289 ERR("Wait returned unexpected value %x\n",rc
);
294 INT exit_now
= FALSE
;
298 ResetEvent(events
[0]);
300 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT
,
301 device
, NULL
, 0, packet
->reportBuffer
,
302 ext
->preparseData
->caps
.InputReportByteLength
, TRUE
, NULL
,
305 IoSetCompletionRoutine(irp
, read_Completion
, events
[0], TRUE
, TRUE
, TRUE
);
306 ntrc
= IoCallDriver(device
, irp
);
308 if (ntrc
== STATUS_PENDING
)
310 WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
313 rc
= WaitForSingleObject(ext
->halt_event
, 0);
314 if (rc
== WAIT_OBJECT_0
)
317 if (!exit_now
&& irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
319 packet
->reportBufferLen
= irp
->IoStatus
.Information
;
320 if (ext
->preparseData
->InputReports
[0].reportID
)
321 packet
->reportId
= packet
->reportBuffer
[0];
323 packet
->reportId
= 0;
324 RingBuffer_Write(ext
->ring_buffer
, packet
);
325 HID_Device_processQueue(device
);
328 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
335 /* FIXME: releasing packet requires IRP cancellation support */
336 CloseHandle(events
[0]);
338 TRACE("Device thread exiting\n");
342 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
344 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
345 ext
->halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
346 ext
->thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
349 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
351 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
352 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
354 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
355 irp
->IoStatus
.Information
= 0;
359 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &base
->information
, sizeof(HID_COLLECTION_INFORMATION
));
360 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
361 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
363 return STATUS_SUCCESS
;
366 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
368 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
370 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< base
->preparseData
->dwSize
)
372 irp
->IoStatus
.u
.Status
= STATUS_INVALID_BUFFER_SIZE
;
373 irp
->IoStatus
.Information
= 0;
377 memcpy(irp
->UserBuffer
, base
->preparseData
, base
->preparseData
->dwSize
);
378 irp
->IoStatus
.Information
= base
->preparseData
->dwSize
;
379 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
381 return STATUS_SUCCESS
;
384 static NTSTATUS
handle_minidriver_string(DEVICE_OBJECT
*device
, IRP
*irp
, SHORT index
)
386 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
391 InputBuffer
= MAKELONG(index
, 0);
392 status
= call_minidriver(IOCTL_HID_GET_STRING
, device
, ULongToPtr(InputBuffer
), sizeof(InputBuffer
), buffer
, sizeof(buffer
));
394 if (status
== STATUS_SUCCESS
)
396 WCHAR
*out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
397 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
398 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
399 lstrcpynW(out_buffer
, buffer
, length
);
400 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
402 irp
->IoStatus
.u
.Status
= status
;
404 return STATUS_SUCCESS
;
407 static NTSTATUS
HID_get_feature(DEVICE_OBJECT
*device
, IRP
*irp
)
409 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
410 HID_XFER_PACKET
*packet
;
412 NTSTATUS rc
= STATUS_SUCCESS
;
415 irp
->IoStatus
.Information
= 0;
417 out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
418 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, out_buffer
);
420 len
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
421 packet
= HeapAlloc(GetProcessHeap(), 0, len
);
422 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
423 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
424 packet
->reportId
= out_buffer
[0];
426 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
->reportId
, packet
->reportBufferLen
, packet
->reportBuffer
);
428 rc
= call_minidriver(IOCTL_HID_GET_FEATURE
, device
, NULL
, 0, packet
, sizeof(*packet
));
430 irp
->IoStatus
.u
.Status
= rc
;
431 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
433 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
434 memcpy(out_buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
437 irp
->IoStatus
.Information
= 0;
439 TRACE_(hid_report
)("Result 0x%x get %li bytes\n", rc
, irp
->IoStatus
.Information
);
441 HeapFree(GetProcessHeap(), 0, packet
);
446 static NTSTATUS
HID_set_to_device(DEVICE_OBJECT
*device
, IRP
*irp
)
448 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
449 HID_XFER_PACKET packet
;
452 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
, irp
->AssociatedIrp
.SystemBuffer
);
453 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
454 if (packet
.reportId
== 0)
456 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
457 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
- 1;
461 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
462 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
464 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
466 rc
= call_minidriver(irpsp
->Parameters
.DeviceIoControl
.IoControlCode
,
467 device
, NULL
, 0, &packet
, sizeof(packet
));
469 irp
->IoStatus
.u
.Status
= rc
;
470 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
471 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
473 irp
->IoStatus
.Information
= 0;
475 TRACE_(hid_report
)("Result 0x%x set %li bytes\n", rc
, irp
->IoStatus
.Information
);
480 NTSTATUS WINAPI
HID_Device_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
482 NTSTATUS rc
= STATUS_SUCCESS
;
483 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
484 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
486 irp
->IoStatus
.Information
= 0;
488 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
490 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
492 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
493 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
494 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
496 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
497 irp
->IoStatus
.Information
= 0;
500 *((ULONG
*)irp
->AssociatedIrp
.SystemBuffer
) = extension
->poll_interval
;
501 irp
->IoStatus
.Information
= sizeof(ULONG
);
502 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
504 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
507 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
508 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
510 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_TOO_SMALL
;
513 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
514 if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
516 extension
->poll_interval
= poll_interval
;
517 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
520 irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
523 case IOCTL_HID_GET_PRODUCT_STRING
:
525 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IPRODUCT
);
528 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
530 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_ISERIALNUMBER
);
533 case IOCTL_HID_GET_MANUFACTURER_STRING
:
535 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IMANUFACTURER
);
538 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
540 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, extension
);
543 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
545 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, extension
);
548 case IOCTL_HID_GET_INPUT_REPORT
:
550 HID_XFER_PACKET
*packet
;
551 UINT packet_size
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
552 BYTE
*buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
555 packet
= HeapAlloc(GetProcessHeap(), 0, packet_size
);
557 if (extension
->preparseData
->InputReports
[0].reportID
)
558 packet
->reportId
= buffer
[0];
560 packet
->reportId
= 0;
561 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
562 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
- 1;
564 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, packet
, sizeof(*packet
));
565 if (rc
== STATUS_SUCCESS
)
567 rc
= copy_packet_into_buffer(packet
, buffer
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, &out_length
);
568 irp
->IoStatus
.Information
= out_length
;
571 irp
->IoStatus
.Information
= 0;
572 irp
->IoStatus
.u
.Status
= rc
;
573 HeapFree(GetProcessHeap(), 0, packet
);
576 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
578 irp
->IoStatus
.Information
= 0;
580 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
582 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_OVERFLOW
;
586 rc
= RingBuffer_SetSize(extension
->ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
587 irp
->IoStatus
.u
.Status
= rc
;
591 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
593 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
595 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_TOO_SMALL
;
599 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(extension
->ring_buffer
);
600 rc
= irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
604 case IOCTL_HID_GET_FEATURE
:
605 rc
= HID_get_feature(device
, irp
);
607 case IOCTL_HID_SET_FEATURE
:
608 case IOCTL_HID_SET_OUTPUT_REPORT
:
609 rc
= HID_set_to_device(device
, irp
);
613 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
614 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
615 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
616 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
617 rc
= STATUS_UNSUCCESSFUL
;
622 if (rc
!= STATUS_PENDING
)
623 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
628 NTSTATUS WINAPI
HID_Device_read(DEVICE_OBJECT
*device
, IRP
*irp
)
630 HID_XFER_PACKET
*packet
;
631 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
632 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
633 NTSTATUS rc
= STATUS_SUCCESS
;
634 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
637 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
638 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
640 irp
->IoStatus
.Information
= 0;
641 RingBuffer_ReadNew(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
645 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
648 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
649 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
651 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
652 irp
->IoStatus
.Information
= out_length
;
653 irp
->IoStatus
.u
.Status
= rc
;
654 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
658 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
659 if (extension
->poll_interval
)
661 TRACE_(hid_report
)("Queue irp\n");
662 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.s
.ListEntry
);
667 HID_XFER_PACKET packet
;
668 TRACE("No packet, but opportunistic reads enabled\n");
669 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
670 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
671 packet
.reportBufferLen
= irpsp
->Parameters
.Read
.Length
- 1;
672 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
674 if (rc
== STATUS_SUCCESS
)
676 ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0] = packet
.reportId
;
677 irp
->IoStatus
.Information
= packet
.reportBufferLen
+ 1;
678 irp
->IoStatus
.u
.Status
= rc
;
680 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
683 HeapFree(GetProcessHeap(), 0, packet
);
688 NTSTATUS WINAPI
HID_Device_write(DEVICE_OBJECT
*device
, IRP
*irp
)
690 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
691 HID_XFER_PACKET packet
;
694 irp
->IoStatus
.Information
= 0;
696 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
697 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
698 if (packet
.reportId
== 0)
700 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
701 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
- 1;
705 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
706 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
708 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
710 rc
= call_minidriver(IOCTL_HID_WRITE_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
712 irp
->IoStatus
.u
.Status
= rc
;
713 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
714 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
716 irp
->IoStatus
.Information
= 0;
718 TRACE_(hid_report
)("Result 0x%x wrote %li bytes\n", rc
, irp
->IoStatus
.Information
);
720 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
724 NTSTATUS WINAPI
HID_Device_create(DEVICE_OBJECT
*device
, IRP
*irp
)
726 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
728 TRACE("Open handle on device %p\n", device
);
729 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->ring_buffer
));
730 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
731 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
732 return STATUS_SUCCESS
;
735 NTSTATUS WINAPI
HID_Device_close(DEVICE_OBJECT
*device
, IRP
*irp
)
737 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
738 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
739 TRACE("Close handle on device %p\n", device
);
740 RingBuffer_RemovePointer(ext
->ring_buffer
, ptr
);
741 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
742 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
743 return STATUS_SUCCESS
;