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 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 static NTSTATUS
HID_get_feature(DEVICE_OBJECT
*device
, IRP
*irp
)
435 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
436 HID_XFER_PACKET
*packet
;
438 NTSTATUS rc
= STATUS_SUCCESS
;
441 irp
->IoStatus
.Information
= 0;
443 out_buffer
= (WCHAR
*)(((BYTE
*)irp
->MdlAddress
->StartVa
) + irp
->MdlAddress
->ByteOffset
);
444 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
, out_buffer
);
446 len
= sizeof(*packet
) + irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
447 packet
= HeapAlloc(GetProcessHeap(), 0, len
);
448 packet
->reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
449 packet
->reportBuffer
= ((BYTE
*)packet
) + sizeof(*packet
);
450 packet
->reportId
= out_buffer
[0];
452 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
->reportId
, packet
->reportBufferLen
, packet
->reportBuffer
);
454 rc
= call_minidriver(IOCTL_HID_GET_FEATURE
, device
, NULL
, 0, packet
, len
);
456 irp
->IoStatus
.u
.Status
= rc
;
457 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
458 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
460 irp
->IoStatus
.Information
= 0;
462 TRACE_(hid_report
)("Result 0x%x get %li bytes\n", rc
, irp
->IoStatus
.Information
);
467 static NTSTATUS
HID_set_feature(DEVICE_OBJECT
*device
, IRP
*irp
)
469 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
470 HID_XFER_PACKET packet
;
473 irp
->IoStatus
.Information
= 0;
475 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
, irp
->AssociatedIrp
.SystemBuffer
);
476 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
477 packet
.reportId
= ((char*)irp
->AssociatedIrp
.SystemBuffer
)[0];
478 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
479 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
481 rc
= call_minidriver(IOCTL_HID_SET_FEATURE
, device
, NULL
, 0, &packet
, sizeof(packet
));
483 irp
->IoStatus
.u
.Status
= rc
;
484 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
485 irp
->IoStatus
.Information
= irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
;
487 irp
->IoStatus
.Information
= 0;
489 TRACE_(hid_report
)("Result 0x%x set %li bytes\n", rc
, irp
->IoStatus
.Information
);
494 NTSTATUS WINAPI
HID_Device_ioctl(DEVICE_OBJECT
*device
, IRP
*irp
)
496 NTSTATUS rc
= STATUS_SUCCESS
;
497 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
498 BASE_DEVICE_EXTENSION
*extension
= device
->DeviceExtension
;
500 irp
->IoStatus
.Information
= 0;
502 TRACE("device %p ioctl(%x)\n", device
, irpsp
->Parameters
.DeviceIoControl
.IoControlCode
);
504 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
506 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC
:
507 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
508 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
510 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
511 irp
->IoStatus
.Information
= 0;
514 *((ULONG
*)irp
->AssociatedIrp
.SystemBuffer
) = extension
->poll_interval
;
515 irp
->IoStatus
.Information
= sizeof(ULONG
);
516 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
518 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC
:
521 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
522 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(ULONG
))
524 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_TOO_SMALL
;
527 poll_interval
= *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
;
528 if (poll_interval
== 0)
529 FIXME("Handle opportunistic reads\n");
530 else if (poll_interval
<= MAX_POLL_INTERVAL_MSEC
)
532 extension
->poll_interval
= poll_interval
;
533 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
536 irp
->IoStatus
.u
.Status
= STATUS_INVALID_PARAMETER
;
539 case IOCTL_HID_GET_PRODUCT_STRING
:
541 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IPRODUCT
);
544 case IOCTL_HID_GET_SERIALNUMBER_STRING
:
546 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_ISERIALNUMBER
);
549 case IOCTL_HID_GET_MANUFACTURER_STRING
:
551 rc
= handle_minidriver_string(device
, irp
, HID_STRING_ID_IMANUFACTURER
);
554 case IOCTL_HID_GET_COLLECTION_INFORMATION
:
556 rc
= handle_IOCTL_HID_GET_COLLECTION_INFORMATION(irp
, extension
);
559 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR
:
561 rc
= handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR(irp
, extension
);
564 case IOCTL_HID_GET_INPUT_REPORT
:
566 HID_XFER_PACKET packet
;
567 BYTE
* buffer
= ((BYTE
*)irp
->MdlAddress
->StartVa
) + irp
->MdlAddress
->ByteOffset
;
569 if (extension
->preparseData
->InputReports
[0].reportID
)
570 packet
.reportId
= buffer
[0];
573 packet
.reportBuffer
= buffer
;
574 packet
.reportBufferLen
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
576 call_minidriver(IOCTL_HID_GET_INPUT_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
577 irp
->IoStatus
.Information
= packet
.reportBufferLen
;
578 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
581 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS
:
583 irp
->IoStatus
.Information
= 0;
585 if (irpsp
->Parameters
.DeviceIoControl
.InputBufferLength
!= sizeof(ULONG
))
587 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_OVERFLOW
;
591 rc
= RingBuffer_SetSize(extension
->ring_buffer
, *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
);
592 irp
->IoStatus
.u
.Status
= rc
;
596 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS
:
598 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
600 irp
->IoStatus
.u
.Status
= rc
= STATUS_BUFFER_TOO_SMALL
;
604 *(ULONG
*)irp
->AssociatedIrp
.SystemBuffer
= RingBuffer_GetSize(extension
->ring_buffer
);
605 rc
= irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
609 case IOCTL_HID_GET_FEATURE
:
610 rc
= HID_get_feature(device
, irp
);
612 case IOCTL_HID_SET_FEATURE
:
613 rc
= HID_set_feature(device
, irp
);
617 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
618 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
619 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
620 irp
->IoStatus
.u
.Status
= STATUS_NOT_SUPPORTED
;
621 rc
= STATUS_UNSUCCESSFUL
;
626 if (rc
!= STATUS_PENDING
)
627 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
632 NTSTATUS WINAPI
HID_Device_read(DEVICE_OBJECT
*device
, IRP
*irp
)
634 HID_XFER_PACKET
*packet
;
635 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
636 UINT buffer_size
= RingBuffer_GetBufferSize(ext
->ring_buffer
);
637 NTSTATUS rc
= STATUS_SUCCESS
;
640 packet
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
641 ptr
= PtrToUlong( irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
643 irp
->IoStatus
.Information
= 0;
644 RingBuffer_Read(ext
->ring_buffer
, ptr
, packet
, &buffer_size
);
648 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
649 TRACE_(hid_report
)("Got Packet %p %i\n", packet
->reportBuffer
, packet
->reportBufferLen
);
650 if (irpsp
->Parameters
.Read
.Length
>= packet
->reportBufferLen
)
652 memcpy(irp
->AssociatedIrp
.SystemBuffer
, packet
->reportBuffer
, packet
->reportBufferLen
);
653 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
654 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
658 irp
->IoStatus
.Information
= 0;
659 irp
->IoStatus
.u
.Status
= STATUS_BUFFER_OVERFLOW
;
661 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
665 TRACE_(hid_report
)("Queue irp\n");
666 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.ListEntry
);
669 HeapFree(GetProcessHeap(), 0, packet
);
674 NTSTATUS WINAPI
HID_Device_write(DEVICE_OBJECT
*device
, IRP
*irp
)
676 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
677 HID_XFER_PACKET packet
;
680 irp
->IoStatus
.Information
= 0;
682 TRACE_(hid_report
)("Device %p Buffer length %i Buffer %p\n", device
, irpsp
->Parameters
.Write
.Length
, irp
->AssociatedIrp
.SystemBuffer
);
683 packet
.reportBuffer
= irp
->AssociatedIrp
.SystemBuffer
;
684 packet
.reportId
= ((char*)irp
->AssociatedIrp
.SystemBuffer
)[0];
685 packet
.reportBufferLen
= irpsp
->Parameters
.Write
.Length
;
686 TRACE_(hid_report
)("(id %i, len %i buffer %p)\n", packet
.reportId
, packet
.reportBufferLen
, packet
.reportBuffer
);
688 rc
= call_minidriver(IOCTL_HID_WRITE_REPORT
, device
, NULL
, 0, &packet
, sizeof(packet
));
690 irp
->IoStatus
.u
.Status
= rc
;
691 if (irp
->IoStatus
.u
.Status
== STATUS_SUCCESS
)
692 irp
->IoStatus
.Information
= irpsp
->Parameters
.Write
.Length
;
694 irp
->IoStatus
.Information
= 0;
696 TRACE_(hid_report
)("Result 0x%x wrote %li bytes\n", rc
, irp
->IoStatus
.Information
);
698 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
702 NTSTATUS WINAPI
HID_Device_create(DEVICE_OBJECT
*device
, IRP
*irp
)
704 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
706 TRACE("Open handle on device %p\n", device
);
707 irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
= UlongToPtr(RingBuffer_AddPointer(ext
->ring_buffer
));
708 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
709 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
710 return STATUS_SUCCESS
;
713 NTSTATUS WINAPI
HID_Device_close(DEVICE_OBJECT
*device
, IRP
*irp
)
715 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
716 int ptr
= PtrToUlong(irp
->Tail
.Overlay
.OriginalFileObject
->FsContext
);
717 TRACE("Close handle on device %p\n", device
);
718 RingBuffer_RemovePointer(ext
->ring_buffer
, ptr
);
719 irp
->IoStatus
.u
.Status
= STATUS_SUCCESS
;
720 IoCompleteRequest( irp
, IO_NO_INCREMENT
);
721 return STATUS_SUCCESS
;