2 * WINE HID Pseudo-Plug and Play support
4 * Copyright 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
21 #define NONAMELESSUNION
25 #include "ddk/hidtypes.h"
28 #include "wine/debug.h"
29 #include "wine/list.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
33 static NTSTATUS WINAPI
internalComplete(DEVICE_OBJECT
*deviceObject
, IRP
*irp
,
36 HANDLE event
= context
;
38 return STATUS_MORE_PROCESSING_REQUIRED
;
41 static NTSTATUS
get_device_id(DEVICE_OBJECT
*device
, BUS_QUERY_ID_TYPE type
, WCHAR
*id
)
44 IO_STACK_LOCATION
*irpsp
;
45 IO_STATUS_BLOCK irp_status
;
49 irp
= IoBuildSynchronousFsdRequest(IRP_MJ_PNP
, device
, NULL
, 0, NULL
, NULL
, &irp_status
);
51 return STATUS_NO_MEMORY
;
53 event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
54 irpsp
= IoGetNextIrpStackLocation(irp
);
55 irpsp
->MinorFunction
= IRP_MN_QUERY_ID
;
56 irpsp
->Parameters
.QueryId
.IdType
= type
;
58 IoSetCompletionRoutine(irp
, internalComplete
, event
, TRUE
, TRUE
, TRUE
);
59 status
= IoCallDriver(device
, irp
);
60 if (status
== STATUS_PENDING
)
61 WaitForSingleObject(event
, INFINITE
);
63 lstrcpyW(id
, (WCHAR
*)irp
->IoStatus
.Information
);
64 ExFreePool( (WCHAR
*)irp
->IoStatus
.Information
);
65 status
= irp
->IoStatus
.u
.Status
;
66 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
72 NTSTATUS WINAPI
PNP_AddDevice(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*PDO
)
74 WCHAR device_id
[MAX_DEVICE_ID_LEN
], instance_id
[MAX_DEVICE_ID_LEN
];
75 DEVICE_OBJECT
*device
= NULL
;
77 minidriver
*minidriver
;
78 HID_DEVICE_ATTRIBUTES attr
;
79 BASE_DEVICE_EXTENSION
*ext
= NULL
;
80 HID_DESCRIPTOR descriptor
;
81 BYTE
*reportDescriptor
;
84 if ((status
= get_device_id(PDO
, BusQueryDeviceID
, device_id
)))
86 ERR("Failed to get PDO device id, status %#x.\n", status
);
90 if ((status
= get_device_id(PDO
, BusQueryInstanceID
, instance_id
)))
92 ERR("Failed to get PDO instance id, status %#x.\n", status
);
96 TRACE("Adding device to PDO %p, id %s\\%s.\n", PDO
, debugstr_w(device_id
), debugstr_w(instance_id
));
97 minidriver
= find_minidriver(driver
);
99 status
= HID_CreateDevice(PDO
, &minidriver
->minidriver
, &device
);
100 if (status
!= STATUS_SUCCESS
)
102 ERR("Failed to create HID object (%x)\n",status
);
106 ext
= device
->DeviceExtension
;
107 InitializeListHead(&ext
->irp_queue
);
108 KeInitializeSpinLock(&ext
->irp_queue_lock
);
110 TRACE("Created device %p\n",device
);
111 status
= minidriver
->AddDevice(minidriver
->minidriver
.DriverObject
, device
);
112 if (status
!= STATUS_SUCCESS
)
114 ERR("Minidriver AddDevice failed (%x)\n",status
);
115 HID_DeleteDevice(device
);
119 status
= call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES
, device
,
120 NULL
, 0, &attr
, sizeof(attr
));
122 if (status
!= STATUS_SUCCESS
)
124 ERR("Minidriver failed to get Attributes(%x)\n",status
);
125 HID_DeleteDevice(device
);
129 ext
->information
.VendorID
= attr
.VendorID
;
130 ext
->information
.ProductID
= attr
.ProductID
;
131 ext
->information
.VersionNumber
= attr
.VersionNumber
;
132 ext
->information
.Polled
= minidriver
->minidriver
.DevicesArePolled
;
134 status
= call_minidriver(IOCTL_HID_GET_DEVICE_DESCRIPTOR
, device
, NULL
, 0,
135 &descriptor
, sizeof(descriptor
));
136 if (status
!= STATUS_SUCCESS
)
138 ERR("Cannot get Device Descriptor(%x)\n",status
);
139 HID_DeleteDevice(device
);
142 for (i
= 0; i
< descriptor
.bNumDescriptors
; i
++)
143 if (descriptor
.DescriptorList
[i
].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
)
146 if (i
>= descriptor
.bNumDescriptors
)
148 ERR("No Report Descriptor found in reply\n");
149 HID_DeleteDevice(device
);
153 reportDescriptor
= HeapAlloc(GetProcessHeap(), 0, descriptor
.DescriptorList
[i
].wReportLength
);
154 status
= call_minidriver(IOCTL_HID_GET_REPORT_DESCRIPTOR
, device
, NULL
, 0,
155 reportDescriptor
, descriptor
.DescriptorList
[i
].wReportLength
);
156 if (status
!= STATUS_SUCCESS
)
158 ERR("Cannot get Report Descriptor(%x)\n",status
);
159 HID_DeleteDevice(device
);
160 HeapFree(GetProcessHeap(), 0, reportDescriptor
);
164 ext
->preparseData
= ParseDescriptor(reportDescriptor
, descriptor
.DescriptorList
[i
].wReportLength
);
166 HeapFree(GetProcessHeap(), 0, reportDescriptor
);
167 if (!ext
->preparseData
)
169 ERR("Cannot parse Report Descriptor\n");
170 HID_DeleteDevice(device
);
171 return STATUS_NOT_SUPPORTED
;
174 ext
->information
.DescriptorSize
= ext
->preparseData
->dwSize
;
176 lstrcpyW(ext
->instance_id
, instance_id
);
178 lstrcpyW(ext
->device_id
, L
"HID");
179 lstrcatW(ext
->device_id
, L
"\\");
180 lstrcatW(ext
->device_id
, wcschr(device_id
, '\\') + 1);
182 HID_LinkDevice(device
);
184 ext
->poll_interval
= DEFAULT_POLL_INTERVAL
;
186 ext
->ring_buffer
= RingBuffer_Create(sizeof(HID_XFER_PACKET
) + ext
->preparseData
->caps
.InputReportByteLength
);
188 HID_StartDeviceThread(device
);
190 return STATUS_SUCCESS
;
193 static NTSTATUS
remove_device(minidriver
*minidriver
, DEVICE_OBJECT
*device
, IRP
*irp
)
195 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
196 NTSTATUS rc
= STATUS_NOT_SUPPORTED
;
198 rc
= IoSetDeviceInterfaceState(&ext
->link_name
, FALSE
);
201 FIXME("failed to disable interface %x\n", rc
);
206 IoSetDeviceInterfaceState(&ext
->mouse_link_name
, FALSE
);
209 rc
= minidriver
->PNPDispatch(device
, irp
);
210 HID_DeleteDevice(device
);
214 NTSTATUS WINAPI
HID_PNP_Dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
216 NTSTATUS rc
= STATUS_NOT_SUPPORTED
;
217 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
218 minidriver
*minidriver
= find_minidriver(device
->DriverObject
);
220 TRACE("%p, %p\n", device
, irp
);
222 switch(irpsp
->MinorFunction
)
224 case IRP_MN_QUERY_ID
:
226 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
227 WCHAR
*id
= ExAllocatePool(PagedPool
, sizeof(WCHAR
) * REGSTR_VAL_MAX_HCID_LEN
);
228 TRACE("IRP_MN_QUERY_ID[%i]\n", irpsp
->Parameters
.QueryId
.IdType
);
229 switch (irpsp
->Parameters
.QueryId
.IdType
)
231 case BusQueryHardwareIDs
:
232 case BusQueryCompatibleIDs
:
236 /* Device instance ID */
237 lstrcpyW(ptr
, ext
->device_id
);
238 ptr
+= lstrlenW(ext
->device_id
);
239 lstrcpyW(ptr
, L
"\\");
241 lstrcpyW(ptr
, ext
->instance_id
);
242 ptr
+= lstrlenW(ext
->instance_id
) + 1;
244 lstrcpyW(ptr
, ext
->device_id
);
245 ptr
+= lstrlenW(ext
->device_id
) + 1;
247 lstrcpyW(ptr
, L
"HID");
248 ptr
+= lstrlenW(L
"HID") + 1;
250 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
254 case BusQueryDeviceID
:
255 lstrcpyW(id
, ext
->device_id
);
256 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
259 case BusQueryInstanceID
:
260 lstrcpyW(id
, ext
->instance_id
);
261 irp
->IoStatus
.Information
= (ULONG_PTR
)id
;
265 case BusQueryContainerID
:
266 case BusQueryDeviceSerialNumber
:
267 FIXME("unimplemented id type %#x\n", irpsp
->Parameters
.QueryId
.IdType
);
273 case IRP_MN_START_DEVICE
:
275 BASE_DEVICE_EXTENSION
*ext
= device
->DeviceExtension
;
277 rc
= minidriver
->PNPDispatch(device
, irp
);
279 IoSetDeviceInterfaceState(&ext
->link_name
, TRUE
);
281 IoSetDeviceInterfaceState(&ext
->mouse_link_name
, TRUE
);
284 case IRP_MN_REMOVE_DEVICE
:
286 return remove_device(minidriver
, device
, irp
);
290 /* Forward IRP to the minidriver */
291 return minidriver
->PNPDispatch(device
, irp
);
295 irp
->IoStatus
.u
.Status
= rc
;
296 IoCompleteRequest( irp
, IO_NO_INCREMENT
);