mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / hidclass.sys / pnp.c
blob5a4ebf8b42b63cf2586e6504d16e26fd7f3c1410
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 "ddk/wdm.h"
27 #include "regstr.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,
34 void *context)
36 HANDLE event = context;
37 SetEvent(event);
38 return STATUS_MORE_PROCESSING_REQUIRED;
41 static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR *id)
43 NTSTATUS status;
44 IO_STACK_LOCATION *irpsp;
45 IO_STATUS_BLOCK irp_status;
46 HANDLE event;
47 IRP *irp;
49 irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status);
50 if (irp == NULL)
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 );
67 CloseHandle(event);
69 return status;
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;
76 NTSTATUS status;
77 minidriver *minidriver;
78 HID_DEVICE_ATTRIBUTES attr;
79 BASE_DEVICE_EXTENSION *ext = NULL;
80 HID_DESCRIPTOR descriptor;
81 BYTE *reportDescriptor;
82 INT i;
84 if ((status = get_device_id(PDO, BusQueryDeviceID, device_id)))
86 ERR("Failed to get PDO device id, status %#x.\n", status);
87 return status;
90 if ((status = get_device_id(PDO, BusQueryInstanceID, instance_id)))
92 ERR("Failed to get PDO instance id, status %#x.\n", status);
93 return 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);
103 return 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);
116 return status;
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);
126 return status;
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);
140 return status;
142 for (i = 0; i < descriptor.bNumDescriptors; i++)
143 if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE)
144 break;
146 if (i >= descriptor.bNumDescriptors)
148 ERR("No Report Descriptor found in reply\n");
149 HID_DeleteDevice(device);
150 return status;
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);
161 return status;
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);
199 if (rc)
201 FIXME("failed to disable interface %x\n", rc);
202 return rc;
205 if (ext->is_mouse)
206 IoSetDeviceInterfaceState(&ext->mouse_link_name, FALSE);
208 if (irp)
209 rc = minidriver->PNPDispatch(device, irp);
210 HID_DeleteDevice(device);
211 return rc;
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:
234 WCHAR *ptr;
235 ptr = id;
236 /* Device instance ID */
237 lstrcpyW(ptr, ext->device_id);
238 ptr += lstrlenW(ext->device_id);
239 lstrcpyW(ptr, L"\\");
240 ptr += 1;
241 lstrcpyW(ptr, ext->instance_id);
242 ptr += lstrlenW(ext->instance_id) + 1;
243 /* Device ID */
244 lstrcpyW(ptr, ext->device_id);
245 ptr += lstrlenW(ext->device_id) + 1;
246 /* Bus ID */
247 lstrcpyW(ptr, L"HID");
248 ptr += lstrlenW(L"HID") + 1;
249 *ptr = 0;
250 irp->IoStatus.Information = (ULONG_PTR)id;
251 rc = STATUS_SUCCESS;
252 break;
254 case BusQueryDeviceID:
255 lstrcpyW(id, ext->device_id);
256 irp->IoStatus.Information = (ULONG_PTR)id;
257 rc = STATUS_SUCCESS;
258 break;
259 case BusQueryInstanceID:
260 lstrcpyW(id, ext->instance_id);
261 irp->IoStatus.Information = (ULONG_PTR)id;
262 rc = STATUS_SUCCESS;
263 break;
265 case BusQueryContainerID:
266 case BusQueryDeviceSerialNumber:
267 FIXME("unimplemented id type %#x\n", irpsp->Parameters.QueryId.IdType);
268 ExFreePool(id);
269 break;
271 break;
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);
280 if (ext->is_mouse)
281 IoSetDeviceInterfaceState(&ext->mouse_link_name, TRUE);
282 return rc;
284 case IRP_MN_REMOVE_DEVICE:
286 return remove_device(minidriver, device, irp);
288 default:
290 /* Forward IRP to the minidriver */
291 return minidriver->PNPDispatch(device, irp);
295 irp->IoStatus.u.Status = rc;
296 IoCompleteRequest( irp, IO_NO_INCREMENT );
297 return rc;