hidclass.sys: Handle failure to parse preparseData.
[wine.git] / dlls / hidclass.sys / pnp.c
blob5de75223a46d931398171fb2b5d70632d525fbf3
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 "wine/debug.h"
27 #include "wine/unicode.h"
28 #include "wine/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(hid);
32 typedef struct _NATIVE_DEVICE {
33 struct list entry;
35 DWORD vidpid;
36 DEVICE_OBJECT *PDO;
37 DEVICE_OBJECT *FDO;
38 HID_MINIDRIVER_REGISTRATION *minidriver;
40 } NATIVE_DEVICE;
42 static struct list tracked_devices = LIST_INIT(tracked_devices);
44 static NTSTATUS WINAPI internalComplete(DEVICE_OBJECT *deviceObject, IRP *irp,
45 void *context )
47 SetEvent(irp->UserEvent);
48 return STATUS_MORE_PROCESSING_REQUIRED;
51 static NTSTATUS SendDeviceIRP(DEVICE_OBJECT* device, IRP *irp)
53 NTSTATUS status;
54 IO_STACK_LOCATION *irpsp;
55 HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
57 irp->UserEvent = event;
58 irpsp = IoGetNextIrpStackLocation(irp);
59 irpsp->CompletionRoutine = internalComplete;
60 irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
62 IoCallDriver(device, irp);
64 if (irp->IoStatus.u.Status == STATUS_PENDING)
65 WaitForSingleObject(event, INFINITE);
67 status = irp->IoStatus.u.Status;
68 IoCompleteRequest(irp, IO_NO_INCREMENT );
69 CloseHandle(event);
70 return status;
73 static NTSTATUS PNP_SendPnPIRP(DEVICE_OBJECT *device, UCHAR minor)
75 IO_STACK_LOCATION *irpsp;
76 IO_STATUS_BLOCK irp_status;
78 IRP *irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status);
80 irpsp = IoGetNextIrpStackLocation(irp);
81 irpsp->MinorFunction = minor;
83 irpsp->Parameters.StartDevice.AllocatedResources = NULL;
84 irpsp->Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
86 return SendDeviceIRP(device, irp);
89 static NTSTATUS PNP_SendPowerIRP(DEVICE_OBJECT *device, DEVICE_POWER_STATE power)
91 IO_STATUS_BLOCK irp_status;
92 IO_STACK_LOCATION *irpsp;
94 IRP *irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER, device, NULL, 0, NULL, NULL, &irp_status);
96 irpsp = IoGetNextIrpStackLocation(irp);
97 irpsp->MinorFunction = IRP_MN_SET_POWER;
99 irpsp->Parameters.Power.Type = DevicePowerState;
100 irpsp->Parameters.Power.State.DeviceState = power;
102 return SendDeviceIRP(device, irp);
105 NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
107 DEVICE_OBJECT *device = NULL;
108 NTSTATUS status;
109 minidriver *minidriver;
110 HID_DEVICE_ATTRIBUTES attr;
111 BASE_DEVICE_EXTENSION *ext = NULL;
112 WCHAR serial[256];
113 WCHAR interface[256];
114 DWORD index = HID_STRING_ID_ISERIALNUMBER;
115 NATIVE_DEVICE *tracked_device, *ptr;
116 INT interface_index = 1;
117 HID_DESCRIPTOR descriptor;
118 BYTE *reportDescriptor;
119 INT i;
121 static const WCHAR ig_fmtW[] = {'I','G','_','%','i',0};
122 static const WCHAR im_fmtW[] = {'I','M','_','%','i',0};
125 TRACE("PDO add device(%p)\n", PDO);
126 minidriver = find_minidriver(driver);
128 status = HID_CreateDevice(PDO, &minidriver->minidriver, &device);
129 if (status != STATUS_SUCCESS)
131 ERR("Failed to create HID object (%x)\n",status);
132 return status;
135 ext = device->DeviceExtension;
136 InitializeListHead(&ext->irp_queue);
138 TRACE("Created device %p\n",device);
139 status = minidriver->AddDevice(minidriver->minidriver.DriverObject, device);
140 if (status != STATUS_SUCCESS)
142 ERR("Minidriver AddDevice failed (%x)\n",status);
143 HID_DeleteDevice(&minidriver->minidriver, device);
144 return status;
147 status = PNP_SendPnPIRP(device, IRP_MN_START_DEVICE);
148 if (status != STATUS_SUCCESS)
150 ERR("Minidriver IRP_MN_START_DEVICE failed (%x)\n",status);
151 HID_DeleteDevice(&minidriver->minidriver, device);
152 return status;
155 status = call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES, device,
156 NULL, 0, &attr, sizeof(attr));
158 if (status != STATUS_SUCCESS)
160 ERR("Minidriver failed to get Attributes(%x)\n",status);
161 PNP_SendPnPIRP(device, IRP_MN_REMOVE_DEVICE);
162 HID_DeleteDevice(&minidriver->minidriver, device);
163 return status;
166 ext->information.VendorID = attr.VendorID;
167 ext->information.ProductID = attr.ProductID;
168 ext->information.VersionNumber = attr.VersionNumber;
169 ext->information.Polled = minidriver->minidriver.DevicesArePolled;
171 tracked_device = HeapAlloc(GetProcessHeap(), 0, sizeof(*tracked_device));
172 tracked_device->vidpid = MAKELONG(attr.VendorID, attr.ProductID);
173 tracked_device->PDO = PDO;
174 tracked_device->FDO = device;
175 tracked_device->minidriver = &minidriver->minidriver;
177 LIST_FOR_EACH_ENTRY(ptr, &tracked_devices, NATIVE_DEVICE, entry)
178 if (ptr->vidpid == tracked_device->vidpid) interface_index++;
180 list_add_tail(&tracked_devices, &tracked_device->entry);
182 status = call_minidriver(IOCTL_HID_GET_DEVICE_DESCRIPTOR, device, NULL, 0,
183 &descriptor, sizeof(descriptor));
184 if (status != STATUS_SUCCESS)
186 ERR("Cannot get Device Descriptor(%x)\n",status);
187 PNP_SendPnPIRP(device, IRP_MN_REMOVE_DEVICE);
188 HID_DeleteDevice(&minidriver->minidriver, device);
189 return status;
191 for (i = 0; i < descriptor.bNumDescriptors; i++)
192 if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE)
193 break;
195 if (i >= descriptor.bNumDescriptors)
197 ERR("No Report Descriptor found in reply\n");
198 PNP_SendPnPIRP(device, IRP_MN_REMOVE_DEVICE);
199 HID_DeleteDevice(&minidriver->minidriver, device);
200 return status;
203 reportDescriptor = HeapAlloc(GetProcessHeap(), 0, descriptor.DescriptorList[i].wReportLength);
204 status = call_minidriver(IOCTL_HID_GET_REPORT_DESCRIPTOR, device, NULL, 0,
205 reportDescriptor, descriptor.DescriptorList[i].wReportLength);
206 if (status != STATUS_SUCCESS)
208 ERR("Cannot get Report Descriptor(%x)\n",status);
209 HID_DeleteDevice(&minidriver->minidriver, device);
210 HeapFree(GetProcessHeap(), 0, reportDescriptor);
211 return status;
214 ext->preparseData = ParseDescriptor(reportDescriptor, descriptor.DescriptorList[0].wReportLength);
216 HeapFree(GetProcessHeap(), 0, reportDescriptor);
217 if (!ext->preparseData)
219 ERR("Cannot parse Report Descriptor\n");
220 HID_DeleteDevice(&minidriver->minidriver, device);
221 return STATUS_NOT_SUPPORTED;
224 ext->information.DescriptorSize = ext->preparseData->dwSize;
226 serial[0] = 0;
227 status = call_minidriver(IOCTL_HID_GET_STRING, device,
228 &index, sizeof(DWORD), serial, sizeof(serial));
230 if (serial[0] == 0)
232 static const WCHAR wZeroSerial[]= {'0','0','0','0',0};
233 lstrcpyW(serial, wZeroSerial);
236 if (ext->preparseData->caps.UsagePage == HID_USAGE_PAGE_GENERIC &&
237 (ext->preparseData->caps.Usage == HID_USAGE_GENERIC_GAMEPAD ||
238 ext->preparseData->caps.Usage == HID_USAGE_GENERIC_JOYSTICK))
239 sprintfW(interface, ig_fmtW, interface_index);
240 else
241 sprintfW(interface, im_fmtW, interface_index);
243 HID_LinkDevice(device, serial, interface);
245 ext->poll_interval = DEFAULT_POLL_INTERVAL;
247 ext->ring_buffer = RingBuffer_Create(sizeof(HID_XFER_PACKET) + ext->preparseData->caps.InputReportByteLength);
249 HID_StartDeviceThread(device);
250 PNP_SendPowerIRP(device, PowerDeviceD0);
252 return STATUS_SUCCESS;
255 void PNP_CleanupPNP(DRIVER_OBJECT *driver)
257 NATIVE_DEVICE *tracked_device, *ptr;
259 LIST_FOR_EACH_ENTRY_SAFE(tracked_device, ptr, &tracked_devices,
260 NATIVE_DEVICE, entry)
262 if (tracked_device->minidriver->DriverObject == driver)
264 list_remove(&tracked_device->entry);
265 PNP_SendPowerIRP(tracked_device->FDO, PowerDeviceD3);
266 PNP_SendPnPIRP(tracked_device->FDO, IRP_MN_REMOVE_DEVICE);
267 HID_DeleteDevice(tracked_device->minidriver, tracked_device->FDO);
268 HeapFree(GetProcessHeap(), 0, tracked_device);