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
, TRUE
, 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 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 WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
342 rc
= WaitForSingleObject(ext
->halt_event
, 0);
343 if (rc
== WAIT_OBJECT_0
)
346 if (!exit_now
&& irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
348 packet
->reportId
= buffer
[0];
349 memcpy(packet
->reportBuffer
, buffer
, ext
->preparseData
->caps
.InputReportByteLength
);
350 RingBuffer_Write(ext
->ring_buffer
, packet
);
351 HID_Device_processQueue(device
);
354 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
360 HeapFree(GetProcessHeap(), 0, packet
);
363 CloseHandle(events
[0]);
365 TRACE("Device thread exiting\n");
369 void HID_StartDeviceThread(DEVICE_OBJECT
*device
)
371 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
372 ext
->halt_event
= CreateEventA(NULL
, TRUE
, FALSE
, NULL
);
373 ext
->thread
= CreateThread(NULL
, 0, hid_device_thread
, device
, 0, NULL
);
376 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_INFORMATION(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
378 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
379 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(HID_COLLECTION_INFORMATION
))
381 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
382 irp
->IoStatus
.Information
= 0;
386 memcpy(irp
->AssociatedIrp
.SystemBuffer
, &base
->information
, sizeof(HID_COLLECTION_INFORMATION
));
387 irp
->IoStatus
.Information
= sizeof(HID_COLLECTION_INFORMATION
);
388 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
390 return STATUS_SUCCESS
;
393 static NTSTATUS
handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(IRP
*irp
, BASE_DEVICE_EXTENSION
*base
)
395 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
397 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< base
->preparseData
->dwSize
)
399 irp
->IoStatus
.u
.Status
= STATUS_INVALID_BUFFER_SIZE
;
400 irp
->IoStatus
.Information
= 0;
404 memcpy(irp
->UserBuffer
, base
->preparseData
, base
->preparseData
->dwSize
);
405 irp
->IoStatus
.Information
= base
->preparseData
->dwSize
;
406 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
408 return STATUS_SUCCESS
;
411 static NTSTATUS
handle_minidriver_string(DEVICE_OBJECT
*device
, IRP
*irp
, SHORT index
)
413 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
418 InputBuffer
= MAKELONG(index
, 0);
419 status
= call_minidriver(IOCTL_HID_GET_STRING
, device
, ULongToPtr(InputBuffer
), sizeof(InputBuffer
), buffer
, sizeof(buffer
));
421 if (status
== STATUS_SUCCESS
)
423 WCHAR
*out_buffer
= (WCHAR
*)(((BYTE
*)irp
->MdlAddress
->StartVa
) + irp
->MdlAddress
->ByteOffset
);
424 int length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/sizeof(WCHAR
);
425 TRACE("got string %s from minidriver\n",debugstr_w(buffer
));
426 lstrcpynW(out_buffer
, buffer
, length
);
427 irp
->IoStatus
.Information
= (lstrlenW(buffer
)+1) * sizeof(WCHAR
);
429 irp
->IoStatus
.u
.Status
= status
;
431 return STATUS_SUCCESS
;
434 static NTSTATUS
HID_get_feature(DEVICE_OBJECT
*device
, IRP
*irp
)
436 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
437 HID_XFER_PACKET
*packet
;
439 NTSTATUS rc
= STATUS_SUCCESS
;
442 irp
->IoStatus
.Information
= 0;
444 out_buffer
= (WCHAR
*)(((BYTE
*)irp
->MdlAddress
->StartVa
) + irp
->MdlAddress
->ByteOffset
);
445 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, out_buffer
);
447 len
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
448 packet
= HeapAlloc(GetProcessHeap(), 0, len
);
449 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
450 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
451 packet
->reportId
= out_buffer
[0];
453 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
->reportId
, packet
->reportBufferLen
, packet
->reportBuffer
);
455 rc
= call_minidriver(IOCTL_HID_GET_FEATURE
, device
, NULL
, 0, packet
, len
);
457 irp
->IoStatus
.u
.Status
= rc
;
458 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
459 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
461 irp
->IoStatus
.Information
= 0;
463 TRACE_(hid_report
)("Result 0x%x get %li bytes\n", rc
, irp
->IoStatus
.Information
);
468 static NTSTATUS
HID_set_feature(DEVICE_OBJECT
*device
, IRP
*irp
)
470 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
471 HID_XFER_PACKET packet
;
474 irp
->IoStatus
.Information
= 0;
476 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
, irp
->AssociatedIrp
.SystemBuffer
);
477 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
478 packet
.reportId
= ((char*)irp
->AssociatedIrp
.SystemBuffer
)[0];
479 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
480 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
482 rc
= call_minidriver(IOCTL_HID_SET_FEATURE
, device
, NULL
, 0, &packet
, sizeof(packet
));
484 irp
->IoStatus
.u
.Status
= rc
;
485 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
486 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
488 irp
->IoStatus
.Information
= 0;
490 TRACE_(hid_report
)("Result 0x%x set %li bytes\n", rc
, irp
->IoStatus
.Information
);
495 NTSTATUS WINAPI
HID_Device_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
497 NTSTATUS rc
= STATUS_SUCCESS
;
498 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
499 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
501 irp
->IoStatus
.Information
= 0;
503 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
505 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
507 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
508 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
509 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
511 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
512 irp
->IoStatus
.Information
= 0;
515 *((ULONG
*)irp
->AssociatedIrp
.SystemBuffer
) = extension
->poll_interval
;
516 irp
->IoStatus
.Information
= sizeof(ULONG
);
517 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
519 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
522 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
523 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
525 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_TOO_SMALL
;
528 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
529 if (poll_interval
== 0)
530 FIXME("Handle opportunistic reads\n");
531 else if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
533 extension
->poll_interval
= poll_interval
;
534 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
537 irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
540 case IOCTL_HID_GET_PRODUCT_STRING
:
542 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IPRODUCT
);
545 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
547 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_ISERIALNUMBER
);
550 case IOCTL_HID_GET_MANUFACTURER_STRING
:
552 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IMANUFACTURER
);
555 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
557 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, extension
);
560 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
562 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, extension
);
565 case IOCTL_HID_GET_INPUT_REPORT
:
567 HID_XFER_PACKET packet
;
568 BYTE
* buffer
= ((BYTE
*)irp
->MdlAddress
->StartVa
) + irp
->MdlAddress
->ByteOffset
;
570 if (extension
->preparseData
->InputReports
[0].reportID
)
571 packet
.reportId
= buffer
[0];
574 packet
.reportBuffer
= buffer
;
575 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
577 call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
578 irp
->IoStatus
.Information
= packet
.reportBufferLen
;
579 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
582 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
584 irp
->IoStatus
.Information
= 0;
586 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
588 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_OVERFLOW
;
592 rc
= RingBuffer_SetSize(extension
->ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
593 irp
->IoStatus
.u
.Status
= rc
;
597 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
599 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
601 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_TOO_SMALL
;
605 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(extension
->ring_buffer
);
606 rc
= irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
610 case IOCTL_HID_GET_FEATURE
:
611 rc
= HID_get_feature(device
, irp
);
613 case IOCTL_HID_SET_FEATURE
:
614 rc
= HID_set_feature(device
, irp
);
618 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
619 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
620 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
621 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
622 rc
= STATUS_UNSUCCESSFUL
;
627 if (rc
!= STATUS_PENDING
)
628 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
633 NTSTATUS WINAPI
HID_Device_read(DEVICE_OBJECT
*device
, IRP
*irp
)
635 HID_XFER_PACKET
*packet
;
636 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
637 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
638 NTSTATUS rc
= STATUS_SUCCESS
;
641 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
642 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
644 irp
->IoStatus
.Information
= 0;
645 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
649 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
650 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
651 if (irpsp
->Parameters
.Read
.Length
>= packet
->reportBufferLen
)
653 memcpy(irp
->AssociatedIrp
.SystemBuffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
654 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
655 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
659 irp
->IoStatus
.Information
= 0;
660 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
662 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
666 TRACE_(hid_report
)("Queue irp\n");
667 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
670 HeapFree(GetProcessHeap(), 0, packet
);
675 NTSTATUS WINAPI
HID_Device_write(DEVICE_OBJECT
*device
, IRP
*irp
)
677 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
678 HID_XFER_PACKET packet
;
681 irp
->IoStatus
.Information
= 0;
683 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
684 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
685 packet
.reportId
= ((char*)irp
->AssociatedIrp
.SystemBuffer
)[0];
686 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
687 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
689 rc
= call_minidriver(IOCTL_HID_WRITE_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
691 irp
->IoStatus
.u
.Status
= rc
;
692 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
693 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
695 irp
->IoStatus
.Information
= 0;
697 TRACE_(hid_report
)("Result 0x%x wrote %li bytes\n", rc
, irp
->IoStatus
.Information
);
699 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
703 NTSTATUS WINAPI
HID_Device_create(DEVICE_OBJECT
*device
, IRP
*irp
)
705 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
707 TRACE("Open handle on device %p\n", device
);
708 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->ring_buffer
));
709 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
710 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
711 return STATUS_SUCCESS
;
714 NTSTATUS WINAPI
HID_Device_close(DEVICE_OBJECT
*device
, IRP
*irp
)
716 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
717 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
718 TRACE("Close handle on device %p\n", device
);
719 RingBuffer_RemovePointer(ext
->ring_buffer
, ptr
);
720 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
721 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
722 return STATUS_SUCCESS
;