makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / hidclass.sys / pnp.c
blob1c130e8dd80464a7c6eed7527ac019159cdff19a
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 const WCHAR device_enumeratorW[] = {'H','I','D',0};
34 static const WCHAR separator_W[] = {'\\',0};
36 static NTSTATUS WINAPI internalComplete(DEVICE_OBJECT *deviceObject, IRP *irp,
37 void *context)
39 HANDLE event = context;
40 SetEvent(event);
41 return STATUS_MORE_PROCESSING_REQUIRED;
44 static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR *id)
46 NTSTATUS status;
47 IO_STACK_LOCATION *irpsp;
48 IO_STATUS_BLOCK irp_status;
49 HANDLE event;
50 IRP *irp;
52 irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status);
53 if (irp == NULL)
54 return STATUS_NO_MEMORY;
56 event = CreateEventA(NULL, FALSE, FALSE, NULL);
57 irpsp = IoGetNextIrpStackLocation(irp);
58 irpsp->MinorFunction = IRP_MN_QUERY_ID;
59 irpsp->Parameters.QueryId.IdType = type;
61 IoSetCompletionRoutine(irp, internalComplete, event, TRUE, TRUE, TRUE);
62 status = IoCallDriver(device, irp);
63 if (status == STATUS_PENDING)
64 WaitForSingleObject(event, INFINITE);
66 lstrcpyW(id, (WCHAR *)irp->IoStatus.Information);
67 ExFreePool( (WCHAR *)irp->IoStatus.Information );
68 status = irp->IoStatus.u.Status;
69 IoCompleteRequest(irp, IO_NO_INCREMENT );
70 CloseHandle(event);
72 return status;
75 NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
77 WCHAR device_id[MAX_DEVICE_ID_LEN], instance_id[MAX_DEVICE_ID_LEN];
78 hid_device *hiddev;
79 DEVICE_OBJECT *device = NULL;
80 NTSTATUS status;
81 minidriver *minidriver;
82 HID_DEVICE_ATTRIBUTES attr;
83 BASE_DEVICE_EXTENSION *ext = NULL;
84 HID_DESCRIPTOR descriptor;
85 BYTE *reportDescriptor;
86 INT i;
88 if ((status = get_device_id(PDO, BusQueryDeviceID, device_id)))
90 ERR("Failed to get PDO device id, status %#x.\n", status);
91 return status;
94 if ((status = get_device_id(PDO, BusQueryInstanceID, instance_id)))
96 ERR("Failed to get PDO instance id, status %#x.\n", status);
97 return status;
100 TRACE("Adding device to PDO %p, id %s\\%s.\n", PDO, debugstr_w(device_id), debugstr_w(instance_id));
101 minidriver = find_minidriver(driver);
103 hiddev = HeapAlloc(GetProcessHeap(), 0, sizeof(*hiddev));
104 if (!hiddev)
105 return STATUS_NO_MEMORY;
107 status = HID_CreateDevice(PDO, &minidriver->minidriver, &hiddev->device);
108 if (status != STATUS_SUCCESS)
110 ERR("Failed to create HID object (%x)\n",status);
111 HeapFree(GetProcessHeap(), 0, hiddev);
112 return status;
114 device = hiddev->device;
116 ext = device->DeviceExtension;
117 InitializeListHead(&ext->irp_queue);
118 KeInitializeSpinLock(&ext->irp_queue_lock);
120 TRACE("Created device %p\n",device);
121 status = minidriver->AddDevice(minidriver->minidriver.DriverObject, device);
122 if (status != STATUS_SUCCESS)
124 ERR("Minidriver AddDevice failed (%x)\n",status);
125 HID_DeleteDevice(device);
126 HeapFree(GetProcessHeap(), 0, hiddev);
127 return status;
130 status = call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES, device,
131 NULL, 0, &attr, sizeof(attr));
133 if (status != STATUS_SUCCESS)
135 ERR("Minidriver failed to get Attributes(%x)\n",status);
136 HID_DeleteDevice(device);
137 HeapFree(GetProcessHeap(), 0, hiddev);
138 return status;
141 ext->information.VendorID = attr.VendorID;
142 ext->information.ProductID = attr.ProductID;
143 ext->information.VersionNumber = attr.VersionNumber;
144 ext->information.Polled = minidriver->minidriver.DevicesArePolled;
146 status = call_minidriver(IOCTL_HID_GET_DEVICE_DESCRIPTOR, device, NULL, 0,
147 &descriptor, sizeof(descriptor));
148 if (status != STATUS_SUCCESS)
150 ERR("Cannot get Device Descriptor(%x)\n",status);
151 HID_DeleteDevice(device);
152 HeapFree(GetProcessHeap(), 0, hiddev);
153 return status;
155 for (i = 0; i < descriptor.bNumDescriptors; i++)
156 if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE)
157 break;
159 if (i >= descriptor.bNumDescriptors)
161 ERR("No Report Descriptor found in reply\n");
162 HID_DeleteDevice(device);
163 HeapFree(GetProcessHeap(), 0, hiddev);
164 return status;
167 reportDescriptor = HeapAlloc(GetProcessHeap(), 0, descriptor.DescriptorList[i].wReportLength);
168 status = call_minidriver(IOCTL_HID_GET_REPORT_DESCRIPTOR, device, NULL, 0,
169 reportDescriptor, descriptor.DescriptorList[i].wReportLength);
170 if (status != STATUS_SUCCESS)
172 ERR("Cannot get Report Descriptor(%x)\n",status);
173 HID_DeleteDevice(device);
174 HeapFree(GetProcessHeap(), 0, reportDescriptor);
175 HeapFree(GetProcessHeap(), 0, hiddev);
176 return status;
179 ext->preparseData = ParseDescriptor(reportDescriptor, descriptor.DescriptorList[0].wReportLength);
181 HeapFree(GetProcessHeap(), 0, reportDescriptor);
182 if (!ext->preparseData)
184 ERR("Cannot parse Report Descriptor\n");
185 HID_DeleteDevice(device);
186 HeapFree(GetProcessHeap(), 0, hiddev);
187 return STATUS_NOT_SUPPORTED;
190 list_add_tail(&(minidriver->device_list), &hiddev->entry);
192 ext->information.DescriptorSize = ext->preparseData->dwSize;
194 lstrcpyW(ext->instance_id, instance_id);
196 lstrcpyW(ext->device_id, device_enumeratorW);
197 lstrcatW(ext->device_id, separator_W);
198 lstrcatW(ext->device_id, wcschr(device_id, '\\') + 1);
200 HID_LinkDevice(device);
202 ext->poll_interval = DEFAULT_POLL_INTERVAL;
204 ext->ring_buffer = RingBuffer_Create(sizeof(HID_XFER_PACKET) + ext->preparseData->caps.InputReportByteLength);
206 HID_StartDeviceThread(device);
208 return STATUS_SUCCESS;
211 NTSTATUS PNP_RemoveDevice(minidriver *minidriver, DEVICE_OBJECT *device, IRP *irp)
213 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
214 hid_device *hiddev;
215 NTSTATUS rc = STATUS_NOT_SUPPORTED;
217 rc = IoSetDeviceInterfaceState(&ext->link_name, FALSE);
218 if (rc)
220 FIXME("failed to disable interface %x\n", rc);
221 return rc;
224 if (ext->is_mouse)
225 IoSetDeviceInterfaceState(&ext->mouse_link_name, FALSE);
227 if (irp)
228 rc = minidriver->PNPDispatch(device, irp);
229 HID_DeleteDevice(device);
230 LIST_FOR_EACH_ENTRY(hiddev, &minidriver->device_list, hid_device, entry)
232 if (hiddev->device == device)
234 list_remove(&hiddev->entry);
235 HeapFree(GetProcessHeap(), 0, hiddev);
236 break;
239 return rc;
242 NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp)
244 NTSTATUS rc = STATUS_NOT_SUPPORTED;
245 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
246 minidriver *minidriver = find_minidriver(device->DriverObject);
248 TRACE("%p, %p\n", device, irp);
250 switch(irpsp->MinorFunction)
252 case IRP_MN_QUERY_ID:
254 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
255 WCHAR *id = ExAllocatePool(PagedPool, sizeof(WCHAR) * REGSTR_VAL_MAX_HCID_LEN);
256 TRACE("IRP_MN_QUERY_ID[%i]\n", irpsp->Parameters.QueryId.IdType);
257 switch (irpsp->Parameters.QueryId.IdType)
259 case BusQueryHardwareIDs:
260 case BusQueryCompatibleIDs:
262 WCHAR *ptr;
263 ptr = id;
264 /* Device instance ID */
265 lstrcpyW(ptr, ext->device_id);
266 ptr += lstrlenW(ext->device_id);
267 lstrcpyW(ptr, separator_W);
268 ptr += 1;
269 lstrcpyW(ptr, ext->instance_id);
270 ptr += lstrlenW(ext->instance_id) + 1;
271 /* Device ID */
272 lstrcpyW(ptr, ext->device_id);
273 ptr += lstrlenW(ext->device_id) + 1;
274 /* Bus ID */
275 lstrcpyW(ptr, device_enumeratorW);
276 ptr += lstrlenW(device_enumeratorW) + 1;
277 *ptr = 0;
278 irp->IoStatus.Information = (ULONG_PTR)id;
279 rc = STATUS_SUCCESS;
280 break;
282 case BusQueryDeviceID:
283 lstrcpyW(id, ext->device_id);
284 irp->IoStatus.Information = (ULONG_PTR)id;
285 rc = STATUS_SUCCESS;
286 break;
287 case BusQueryInstanceID:
288 lstrcpyW(id, ext->instance_id);
289 irp->IoStatus.Information = (ULONG_PTR)id;
290 rc = STATUS_SUCCESS;
291 break;
292 case BusQueryDeviceSerialNumber:
293 FIXME("BusQueryDeviceSerialNumber not implemented\n");
294 ExFreePool(id);
295 break;
297 break;
299 case IRP_MN_START_DEVICE:
301 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
303 rc = minidriver->PNPDispatch(device, irp);
305 IoSetDeviceInterfaceState(&ext->link_name, TRUE);
306 if (ext->is_mouse)
307 IoSetDeviceInterfaceState(&ext->mouse_link_name, TRUE);
308 return rc;
310 case IRP_MN_REMOVE_DEVICE:
312 return PNP_RemoveDevice(minidriver, device, irp);
314 default:
316 /* Forward IRP to the minidriver */
317 return minidriver->PNPDispatch(device, irp);
321 irp->IoStatus.u.Status = rc;
322 IoCompleteRequest( irp, IO_NO_INCREMENT );
323 return rc;