hidclass.sys: Do not send IRP_MJ_POWER ioctls.
[wine.git] / dlls / hidclass.sys / pnp.c
blob8fd5c176970d330084644c0e54f822fbf17e5476
1 /*
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
22 #include <unistd.h>
23 #include <stdarg.h>
24 #include "hid.h"
25 #include "ddk/hidtypes.h"
26 #include "regstr.h"
27 #include "wine/debug.h"
28 #include "wine/unicode.h"
29 #include "wine/list.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(hid);
33 static const WCHAR device_enumeratorW[] = {'H','I','D',0};
34 static const WCHAR separator_W[] = {'\\',0};
35 static const WCHAR device_deviceid_fmtW[] = {'%','s','\\',
36 'v','i','d','_','%','0','4','x','&','p','i','d','_','%', '0','4','x'};
38 typedef struct _NATIVE_DEVICE {
39 struct list entry;
41 DEVICE_OBJECT *PDO;
42 DEVICE_OBJECT *FDO;
43 HID_MINIDRIVER_REGISTRATION *minidriver;
45 } NATIVE_DEVICE;
47 static struct list tracked_devices = LIST_INIT(tracked_devices);
49 static NTSTATUS WINAPI internalComplete(DEVICE_OBJECT *deviceObject, IRP *irp,
50 void *context )
52 SetEvent(irp->UserEvent);
53 return STATUS_MORE_PROCESSING_REQUIRED;
56 static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR **id)
58 NTSTATUS status;
59 IO_STACK_LOCATION *irpsp;
60 IO_STATUS_BLOCK irp_status;
61 IRP *irp;
62 HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
64 irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status);
65 if (irp == NULL)
66 return STATUS_NO_MEMORY;
68 irp->UserEvent = event;
69 irpsp = IoGetNextIrpStackLocation(irp);
70 irpsp->MinorFunction = IRP_MN_QUERY_ID;
71 irpsp->Parameters.QueryId.IdType = type;
72 irpsp->CompletionRoutine = internalComplete;
73 irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
75 IoCallDriver(device, irp);
76 if (irp->IoStatus.u.Status == STATUS_PENDING)
77 WaitForSingleObject(event, INFINITE);
79 *id = (WCHAR*)irp->IoStatus.Information;
80 status = irp->IoStatus.u.Status;
81 IoCompleteRequest(irp, IO_NO_INCREMENT );
82 CloseHandle(event);
84 return status;
87 NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
89 DEVICE_OBJECT *device = NULL;
90 NTSTATUS status;
91 minidriver *minidriver;
92 HID_DEVICE_ATTRIBUTES attr;
93 BASE_DEVICE_EXTENSION *ext = NULL;
94 NATIVE_DEVICE *tracked_device;
95 HID_DESCRIPTOR descriptor;
96 BYTE *reportDescriptor;
97 INT i;
98 WCHAR *PDO_id;
99 WCHAR *id_ptr;
101 status = get_device_id(PDO, BusQueryInstanceID, &PDO_id);
102 if (status != STATUS_SUCCESS)
104 ERR("Failed to get PDO id(%x)\n",status);
105 return status;
108 TRACE("PDO add device(%p:%s)\n", PDO, debugstr_w(PDO_id));
109 minidriver = find_minidriver(driver);
111 status = HID_CreateDevice(PDO, &minidriver->minidriver, &device);
112 if (status != STATUS_SUCCESS)
114 ERR("Failed to create HID object (%x)\n",status);
115 HeapFree(GetProcessHeap(), 0, PDO_id);
116 return status;
119 ext = device->DeviceExtension;
120 InitializeListHead(&ext->irp_queue);
122 TRACE("Created device %p\n",device);
123 status = minidriver->AddDevice(minidriver->minidriver.DriverObject, device);
124 if (status != STATUS_SUCCESS)
126 ERR("Minidriver AddDevice failed (%x)\n",status);
127 HeapFree(GetProcessHeap(), 0, PDO_id);
128 HID_DeleteDevice(&minidriver->minidriver, device);
129 return status;
132 status = call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES, device,
133 NULL, 0, &attr, sizeof(attr));
135 if (status != STATUS_SUCCESS)
137 ERR("Minidriver failed to get Attributes(%x)\n",status);
138 HID_DeleteDevice(&minidriver->minidriver, device);
139 HeapFree(GetProcessHeap(), 0, PDO_id);
140 return status;
143 ext->information.VendorID = attr.VendorID;
144 ext->information.ProductID = attr.ProductID;
145 ext->information.VersionNumber = attr.VersionNumber;
146 ext->information.Polled = minidriver->minidriver.DevicesArePolled;
148 tracked_device = HeapAlloc(GetProcessHeap(), 0, sizeof(*tracked_device));
149 tracked_device->PDO = PDO;
150 tracked_device->FDO = device;
151 tracked_device->minidriver = &minidriver->minidriver;
152 list_add_tail(&tracked_devices, &tracked_device->entry);
154 status = call_minidriver(IOCTL_HID_GET_DEVICE_DESCRIPTOR, device, NULL, 0,
155 &descriptor, sizeof(descriptor));
156 if (status != STATUS_SUCCESS)
158 ERR("Cannot get Device Descriptor(%x)\n",status);
159 HID_DeleteDevice(&minidriver->minidriver, device);
160 HeapFree(GetProcessHeap(), 0, PDO_id);
161 return status;
163 for (i = 0; i < descriptor.bNumDescriptors; i++)
164 if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE)
165 break;
167 if (i >= descriptor.bNumDescriptors)
169 ERR("No Report Descriptor found in reply\n");
170 HID_DeleteDevice(&minidriver->minidriver, device);
171 HeapFree(GetProcessHeap(), 0, PDO_id);
172 return status;
175 reportDescriptor = HeapAlloc(GetProcessHeap(), 0, descriptor.DescriptorList[i].wReportLength);
176 status = call_minidriver(IOCTL_HID_GET_REPORT_DESCRIPTOR, device, NULL, 0,
177 reportDescriptor, descriptor.DescriptorList[i].wReportLength);
178 if (status != STATUS_SUCCESS)
180 ERR("Cannot get Report Descriptor(%x)\n",status);
181 HID_DeleteDevice(&minidriver->minidriver, device);
182 HeapFree(GetProcessHeap(), 0, reportDescriptor);
183 HeapFree(GetProcessHeap(), 0, PDO_id);
184 return status;
187 ext->preparseData = ParseDescriptor(reportDescriptor, descriptor.DescriptorList[0].wReportLength);
189 HeapFree(GetProcessHeap(), 0, reportDescriptor);
190 if (!ext->preparseData)
192 ERR("Cannot parse Report Descriptor\n");
193 HID_DeleteDevice(&minidriver->minidriver, device);
194 HeapFree(GetProcessHeap(), 0, PDO_id);
195 return STATUS_NOT_SUPPORTED;
198 ext->information.DescriptorSize = ext->preparseData->dwSize;
200 lstrcpyW(ext->instance_id, device_enumeratorW);
201 strcatW(ext->instance_id, separator_W);
202 /* Skip the original enumerator */
203 id_ptr = strchrW(PDO_id, '\\');
204 id_ptr++;
205 strcatW(ext->instance_id, id_ptr);
206 HeapFree(GetProcessHeap(), 0, PDO_id);
208 sprintfW(ext->device_id, device_deviceid_fmtW, device_enumeratorW, ext->information.VendorID, ext->information.ProductID);
210 HID_LinkDevice(device);
212 ext->poll_interval = DEFAULT_POLL_INTERVAL;
214 ext->ring_buffer = RingBuffer_Create(sizeof(HID_XFER_PACKET) + ext->preparseData->caps.InputReportByteLength);
216 HID_StartDeviceThread(device);
218 return STATUS_SUCCESS;
221 void PNP_CleanupPNP(DRIVER_OBJECT *driver)
223 NATIVE_DEVICE *tracked_device, *ptr;
225 LIST_FOR_EACH_ENTRY_SAFE(tracked_device, ptr, &tracked_devices,
226 NATIVE_DEVICE, entry)
228 if (tracked_device->minidriver->DriverObject == driver)
230 list_remove(&tracked_device->entry);
231 HID_DeleteDevice(tracked_device->minidriver, tracked_device->FDO);
232 HeapFree(GetProcessHeap(), 0, tracked_device);
237 NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp)
239 NTSTATUS rc = STATUS_NOT_SUPPORTED;
240 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
242 TRACE("%p, %p\n", device, irp);
244 switch(irpsp->MinorFunction)
246 case IRP_MN_QUERY_ID:
248 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
249 WCHAR *id = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR)*REGSTR_VAL_MAX_HCID_LEN);
250 TRACE("IRP_MN_QUERY_ID[%i]\n", irpsp->Parameters.QueryId.IdType);
251 switch (irpsp->Parameters.QueryId.IdType)
253 case BusQueryHardwareIDs:
254 case BusQueryCompatibleIDs:
256 WCHAR *ptr;
257 ptr = id;
258 /* Instance ID */
259 strcpyW(ptr, ext->instance_id);
260 ptr += lstrlenW(ext->instance_id) + 1;
261 /* Device ID */
262 strcpyW(ptr, ext->device_id);
263 ptr += lstrlenW(ext->device_id) + 1;
264 /* Bus ID */
265 strcpyW(ptr, device_enumeratorW);
266 ptr += lstrlenW(device_enumeratorW) + 1;
267 *ptr = 0;
268 irp->IoStatus.Information = (ULONG_PTR)id;
269 rc = STATUS_SUCCESS;
270 break;
272 case BusQueryDeviceID:
273 strcpyW(id, ext->device_id);
274 irp->IoStatus.Information = (ULONG_PTR)id;
275 rc = STATUS_SUCCESS;
276 break;
277 case BusQueryInstanceID:
278 strcpyW(id, ext->instance_id);
279 irp->IoStatus.Information = (ULONG_PTR)id;
280 rc = STATUS_SUCCESS;
281 break;
282 case BusQueryDeviceSerialNumber:
283 FIXME("BusQueryDeviceSerialNumber not implemented\n");
284 HeapFree(GetProcessHeap(), 0, id);
285 break;
287 break;
289 default:
291 /* Forward IRP to the minidriver */
292 minidriver *minidriver = find_minidriver(device->DriverObject);
293 return minidriver->PNPDispatch(device, irp);
297 irp->IoStatus.u.Status = rc;
298 IoCompleteRequest( irp, IO_NO_INCREMENT );
299 return rc;