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"
39 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
40 WINE_DECLARE_DEBUG_CHANNEL(hid_report
);
42 static const WCHAR device_name_fmtW
[] = {'\\','D','e','v','i','c','e',
43 '\\','H','I','D','#','%','p','&','%','p',0};
44 static const WCHAR device_link_fmtW
[] = {'\\','?','?','\\','%','s','#','%','s',0};
45 /* GUID_DEVINTERFACE_HID */
46 static const WCHAR class_guid
[] = {'{','4','D','1','E','5','5','B','2',
47 '-','F','1','6','F','-','1','1','C','F','-','8','8','C','B','-','0','0',
48 '1','1','1','1','0','0','0','0','3','0','}',0};
51 NTSTATUS
HID_CreateDevice(DEVICE_OBJECT
*native_device
, HID_MINIDRIVER_REGISTRATION
*driver
, DEVICE_OBJECT
**device
)
56 BASE_DEVICE_EXTENSION
*ext
;
58 sprintfW(dev_name
, device_name_fmtW
, driver
->DriverObject
, native_device
);
59 RtlInitUnicodeString( &nameW
, dev_name
);
61 TRACE("Create base hid device %s\n", debugstr_w(dev_name
));
63 status
= IoCreateDevice(driver
->DriverObject
, driver
->DeviceExtensionSize
+ sizeof(BASE_DEVICE_EXTENSION
), &nameW
, 0, 0, FALSE
, device
);
66 FIXME( "failed to create device error %x\n", status
);
70 ext
= (*device
)->DeviceExtension
;
72 ext
->deviceExtension
.MiniDeviceExtension
= ext
+ 1;
73 ext
->deviceExtension
.PhysicalDeviceObject
= *device
;
74 ext
->deviceExtension
.NextDeviceObject
= native_device
;
75 ext
->device_name
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(dev_name
) + 1) * sizeof(WCHAR
));
76 lstrcpyW(ext
->device_name
, dev_name
);
77 ext
->link_name
= NULL
;
79 IoAttachDeviceToDeviceStack(*device
, native_device
);
81 return STATUS_SUCCESS
;
84 NTSTATUS
HID_LinkDevice(DEVICE_OBJECT
*device
)
89 UNICODE_STRING nameW
, linkW
;
93 BASE_DEVICE_EXTENSION
*ext
;
95 HidD_GetHidGuid(&hidGuid
);
96 ext
= device
->DeviceExtension
;
98 sprintfW(dev_link
, device_link_fmtW
, ext
->instance_id
, class_guid
);
100 do { if (*ptr
== '\\') *ptr
= '#'; } while (*ptr
++);
103 RtlInitUnicodeString( &nameW
, ext
->device_name
);
104 RtlInitUnicodeString( &linkW
, dev_link
);
106 TRACE("Create link %s\n", debugstr_w(dev_link
));
108 ext
->link_name
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
) * (lstrlenW(dev_link
) + 1));
109 lstrcpyW(ext
->link_name
, dev_link
);
111 status
= IoCreateSymbolicLink( &linkW
, &nameW
);
114 FIXME( "failed to create link error %x\n", status
);
118 devinfo
= SetupDiGetClassDevsW(&GUID_DEVCLASS_HIDCLASS
, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
121 FIXME( "failed to get ClassDevs %x\n", GetLastError());
122 return STATUS_UNSUCCESSFUL
;
124 Data
.cbSize
= sizeof(Data
);
125 if (!SetupDiCreateDeviceInfoW(devinfo
, ext
->instance_id
, &GUID_DEVCLASS_HIDCLASS
, NULL
, NULL
, DICD_INHERIT_CLASSDRVS
, &Data
))
127 if (GetLastError() == ERROR_DEVINST_ALREADY_EXISTS
)
129 SetupDiDestroyDeviceInfoList(devinfo
);
130 return STATUS_SUCCESS
;
132 FIXME( "failed to Create Device Info %x\n", GetLastError());
135 if (!SetupDiRegisterDeviceInfo( devinfo
, &Data
, 0, NULL
, NULL
, NULL
))
137 FIXME( "failed to Register Device Info %x\n", GetLastError());
140 if (!SetupDiCreateDeviceInterfaceW( devinfo
, &Data
, &hidGuid
, NULL
, 0, NULL
))
142 FIXME( "failed to Create Device Interface %x\n", GetLastError());
146 SetupDiDestroyDeviceInfoList(devinfo
);
147 return STATUS_SUCCESS
;
150 SetupDiDestroyDeviceInfoList(devinfo
);
151 return STATUS_UNSUCCESSFUL
;
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
.s
.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 NTSTATUS
copy_packet_into_buffer(HID_XFER_PACKET
*packet
, BYTE
* buffer
, ULONG buffer_length
, ULONG
*out_length
)
203 BOOL zero_id
= (packet
->reportId
== 0);
207 if ((zero_id
&& buffer_length
> packet
->reportBufferLen
) ||
208 (!zero_id
&& buffer_length
>= packet
->reportBufferLen
))
210 if (packet
->reportId
!= 0)
212 memcpy(buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
213 *out_length
= packet
->reportBufferLen
;
218 memcpy(&buffer
[1], packet
->reportBuffer
, packet
->reportBufferLen
);
219 *out_length
= packet
->reportBufferLen
+ 1;
221 return STATUS_SUCCESS
;
224 return STATUS_BUFFER_OVERFLOW
;
227 static void HID_Device_processQueue(DEVICE_OBJECT
*device
)
231 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
232 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
233 HID_XFER_PACKET
*packet
;
235 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
237 entry
= RemoveHeadList(&ext
->irp_queue
);
238 while(entry
!= &ext
->irp_queue
)
241 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
242 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
244 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
249 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
250 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
251 TRACE_(hid_report
)("Processing Request (%i)\n",ptr
);
252 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
253 irp
->IoStatus
.u
.Status
= rc
;
254 irp
->IoStatus
.Information
= out_length
;
258 irp
->IoStatus
.Information
= 0;
259 irp
->IoStatus
.u
.Status
= STATUS_UNSUCCESSFUL
;
261 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
262 entry
= RemoveHeadList(&ext
->irp_queue
);
264 HeapFree(GetProcessHeap(), 0, packet
);
267 static NTSTATUS WINAPI
read_Completion(DEVICE_OBJECT
*deviceObject
, IRP
*irp
, void *context
)
269 HANDLE event
= context
;
271 return STATUS_MORE_PROCESSING_REQUIRED
;
274 static DWORD CALLBACK
hid_device_thread(void *args
)
276 DEVICE_OBJECT
*device
= (DEVICE_OBJECT
*)args
;
279 IO_STATUS_BLOCK irp_status
;
280 HID_XFER_PACKET
*packet
;
285 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
286 events
[0] = CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
287 events
[1] = ext
->halt_event
;
289 packet
= HeapAlloc(GetProcessHeap(), 0, sizeof(*packet
) + ext
->preparseData
->caps
.InputReportByteLength
);
290 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
292 if (ext
->information
.Polled
)
296 ResetEvent(events
[0]);
298 packet
->reportBufferLen
= ext
->preparseData
->caps
.InputReportByteLength
;
299 packet
->reportId
= 0;
301 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_GET_INPUT_REPORT
,
302 device
, NULL
, 0, packet
, sizeof(*packet
), TRUE
, NULL
,
305 IoSetCompletionRoutine(irp
, read_Completion
, events
[0], TRUE
, TRUE
, TRUE
);
306 ntrc
= IoCallDriver(device
, irp
);
308 if (ntrc
== STATUS_PENDING
)
309 WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
311 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
313 RingBuffer_Write(ext
->ring_buffer
, packet
);
314 HID_Device_processQueue(device
);
317 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
319 rc
= WaitForSingleObject(ext
->halt_event
, ext
->poll_interval
);
321 if (rc
== WAIT_OBJECT_0
)
323 else if (rc
!= WAIT_TIMEOUT
)
324 ERR("Wait returned unexpected value %x\n",rc
);
329 INT exit_now
= FALSE
;
333 ResetEvent(events
[0]);
335 irp
= IoBuildDeviceIoControlRequest(IOCTL_HID_READ_REPORT
,
336 device
, NULL
, 0, packet
->reportBuffer
,
337 ext
->preparseData
->caps
.InputReportByteLength
, TRUE
, NULL
,
340 IoSetCompletionRoutine(irp
, read_Completion
, events
[0], TRUE
, TRUE
, TRUE
);
341 ntrc
= IoCallDriver(device
, irp
);
343 if (ntrc
== STATUS_PENDING
)
345 WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
348 rc
= WaitForSingleObject(ext
->halt_event
, 0);
349 if (rc
== WAIT_OBJECT_0
)
352 if (!exit_now
&& irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
354 packet
->reportBufferLen
= irp
->IoStatus
.Information
;
355 if (ext
->preparseData
->InputReports
[0].reportID
)
356 packet
->reportId
= packet
->reportBuffer
[0];
358 packet
->reportId
= 0;
359 RingBuffer_Write(ext
->ring_buffer
, packet
);
360 HID_Device_processQueue(device
);
363 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
370 /* FIXME: releasing packet requires IRP cancellation support */
371 CloseHandle(events
[0]);
373 TRACE("Device thread exiting\n");
377 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
379 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
380 ext
->halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
381 ext
->thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
384 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
386 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
387 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
389 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
390 irp
->IoStatus
.Information
= 0;
394 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &base
->information
, sizeof(HID_COLLECTION_INFORMATION
));
395 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
396 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
398 return STATUS_SUCCESS
;
401 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
403 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
405 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< base
->preparseData
->dwSize
)
407 irp
->IoStatus
.u
.Status
= STATUS_INVALID_BUFFER_SIZE
;
408 irp
->IoStatus
.Information
= 0;
412 memcpy(irp
->UserBuffer
, base
->preparseData
, base
->preparseData
->dwSize
);
413 irp
->IoStatus
.Information
= base
->preparseData
->dwSize
;
414 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
416 return STATUS_SUCCESS
;
419 static NTSTATUS
handle_minidriver_string(DEVICE_OBJECT
*device
, IRP
*irp
, SHORT index
)
421 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
426 InputBuffer
= MAKELONG(index
, 0);
427 status
= call_minidriver(IOCTL_HID_GET_STRING
, device
, ULongToPtr(InputBuffer
), sizeof(InputBuffer
), buffer
, sizeof(buffer
));
429 if (status
== STATUS_SUCCESS
)
431 WCHAR
*out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
432 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
433 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
434 lstrcpynW(out_buffer
, buffer
, length
);
435 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
437 irp
->IoStatus
.u
.Status
= status
;
439 return STATUS_SUCCESS
;
442 static NTSTATUS
HID_get_feature(DEVICE_OBJECT
*device
, IRP
*irp
)
444 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
445 HID_XFER_PACKET
*packet
;
447 NTSTATUS rc
= STATUS_SUCCESS
;
450 irp
->IoStatus
.Information
= 0;
452 out_buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
453 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, out_buffer
);
455 len
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
456 packet
= HeapAlloc(GetProcessHeap(), 0, len
);
457 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
458 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
459 packet
->reportId
= out_buffer
[0];
461 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
->reportId
, packet
->reportBufferLen
, packet
->reportBuffer
);
463 rc
= call_minidriver(IOCTL_HID_GET_FEATURE
, device
, NULL
, 0, packet
, sizeof(*packet
));
465 irp
->IoStatus
.u
.Status
= rc
;
466 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
468 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
469 memcpy(out_buffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
472 irp
->IoStatus
.Information
= 0;
474 TRACE_(hid_report
)("Result 0x%x get %li bytes\n", rc
, irp
->IoStatus
.Information
);
476 HeapFree(GetProcessHeap(), 0, packet
);
481 static NTSTATUS
HID_set_to_device(DEVICE_OBJECT
*device
, IRP
*irp
)
483 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
484 HID_XFER_PACKET packet
;
487 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
, irp
->AssociatedIrp
.SystemBuffer
);
488 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
489 if (packet
.reportId
== 0)
491 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
492 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
- 1;
496 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
497 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
499 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
501 rc
= call_minidriver(irpsp
->Parameters
.DeviceIoControl
.IoControlCode
,
502 device
, NULL
, 0, &packet
, sizeof(packet
));
504 irp
->IoStatus
.u
.Status
= rc
;
505 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
506 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
508 irp
->IoStatus
.Information
= 0;
510 TRACE_(hid_report
)("Result 0x%x set %li bytes\n", rc
, irp
->IoStatus
.Information
);
515 NTSTATUS WINAPI
HID_Device_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
517 NTSTATUS rc
= STATUS_SUCCESS
;
518 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
519 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
521 irp
->IoStatus
.Information
= 0;
523 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
525 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
527 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
528 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
529 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
531 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
532 irp
->IoStatus
.Information
= 0;
535 *((ULONG
*)irp
->AssociatedIrp
.SystemBuffer
) = extension
->poll_interval
;
536 irp
->IoStatus
.Information
= sizeof(ULONG
);
537 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
539 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
542 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
543 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
545 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_TOO_SMALL
;
548 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
549 if (poll_interval
== 0)
550 FIXME("Handle opportunistic reads\n");
551 else if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
553 extension
->poll_interval
= poll_interval
;
554 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
557 irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
560 case IOCTL_HID_GET_PRODUCT_STRING
:
562 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IPRODUCT
);
565 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
567 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_ISERIALNUMBER
);
570 case IOCTL_HID_GET_MANUFACTURER_STRING
:
572 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IMANUFACTURER
);
575 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
577 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, extension
);
580 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
582 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, extension
);
585 case IOCTL_HID_GET_INPUT_REPORT
:
587 HID_XFER_PACKET
*packet
;
588 UINT packet_size
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
589 BYTE
*buffer
= MmGetSystemAddressForMdlSafe(irp
->MdlAddress
, NormalPagePriority
);
592 packet
= HeapAlloc(GetProcessHeap(), 0, packet_size
);
594 if (extension
->preparseData
->InputReports
[0].reportID
)
595 packet
->reportId
= buffer
[0];
597 packet
->reportId
= 0;
598 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
599 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
- 1;
601 rc
= call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, packet
, sizeof(*packet
));
602 if (rc
== STATUS_SUCCESS
)
604 rc
= copy_packet_into_buffer(packet
, buffer
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, &out_length
);
605 irp
->IoStatus
.Information
= out_length
;
608 irp
->IoStatus
.Information
= 0;
609 irp
->IoStatus
.u
.Status
= rc
;
610 HeapFree(GetProcessHeap(), 0, packet
);
613 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
615 irp
->IoStatus
.Information
= 0;
617 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
619 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_OVERFLOW
;
623 rc
= RingBuffer_SetSize(extension
->ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
624 irp
->IoStatus
.u
.Status
= rc
;
628 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
630 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
632 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_TOO_SMALL
;
636 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(extension
->ring_buffer
);
637 rc
= irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
641 case IOCTL_HID_GET_FEATURE
:
642 rc
= HID_get_feature(device
, irp
);
644 case IOCTL_HID_SET_FEATURE
:
645 case IOCTL_HID_SET_OUTPUT_REPORT
:
646 rc
= HID_set_to_device(device
, irp
);
650 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
651 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
652 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
653 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
654 rc
= STATUS_UNSUCCESSFUL
;
659 if (rc
!= STATUS_PENDING
)
660 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
665 NTSTATUS WINAPI
HID_Device_read(DEVICE_OBJECT
*device
, IRP
*irp
)
667 HID_XFER_PACKET
*packet
;
668 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
669 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
670 NTSTATUS rc
= STATUS_SUCCESS
;
673 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
674 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
676 irp
->IoStatus
.Information
= 0;
677 RingBuffer_ReadNew(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
681 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
684 packet
->reportBuffer
= (BYTE
*)packet
+ sizeof(*packet
);
685 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
687 rc
= copy_packet_into_buffer(packet
, irp
->AssociatedIrp
.SystemBuffer
, irpsp
->Parameters
.Read
.Length
, &out_length
);
688 irp
->IoStatus
.Information
= out_length
;
689 irp
->IoStatus
.u
.Status
= rc
;
690 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
694 TRACE_(hid_report
)("Queue irp\n");
695 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.s
.ListEntry
);
698 HeapFree(GetProcessHeap(), 0, packet
);
703 NTSTATUS WINAPI
HID_Device_write(DEVICE_OBJECT
*device
, IRP
*irp
)
705 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
706 HID_XFER_PACKET packet
;
709 irp
->IoStatus
.Information
= 0;
711 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
712 packet
.reportId
= ((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[0];
713 if (packet
.reportId
== 0)
715 packet
.reportBuffer
= &((BYTE
*)irp
->AssociatedIrp
.SystemBuffer
)[1];
716 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
- 1;
720 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
721 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
723 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
725 rc
= call_minidriver(IOCTL_HID_WRITE_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
727 irp
->IoStatus
.u
.Status
= rc
;
728 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
729 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
731 irp
->IoStatus
.Information
= 0;
733 TRACE_(hid_report
)("Result 0x%x wrote %li bytes\n", rc
, irp
->IoStatus
.Information
);
735 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
739 NTSTATUS WINAPI
HID_Device_create(DEVICE_OBJECT
*device
, IRP
*irp
)
741 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
743 TRACE("Open handle on device %p\n", device
);
744 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->ring_buffer
));
745 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
746 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
747 return STATUS_SUCCESS
;
750 NTSTATUS WINAPI
HID_Device_close(DEVICE_OBJECT
*device
, IRP
*irp
)
752 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
753 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
754 TRACE("Close handle on device %p\n", device
);
755 RingBuffer_RemovePointer(ext
->ring_buffer
, ptr
);
756 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
757 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
758 return STATUS_SUCCESS
;