hidclass.sys: Stub to handle IRP_MJ_WRITE on HID devices.
[wine.git] / dlls / hidclass.sys / pnp.c
blobc3d6f643f51a8ab140a6e1a9f9d4b6b4530d6d39
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 NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
46 DEVICE_OBJECT *device = NULL;
47 NTSTATUS status;
48 minidriver *minidriver;
49 HID_DEVICE_ATTRIBUTES attr;
50 BASE_DEVICE_EXTENSION *ext = NULL;
51 WCHAR serial[256];
52 WCHAR interface[256];
53 DWORD index = HID_STRING_ID_ISERIALNUMBER;
54 NATIVE_DEVICE *tracked_device, *ptr;
55 INT interface_index = 1;
56 HID_DESCRIPTOR descriptor;
57 BYTE *reportDescriptor;
58 INT i;
60 static const WCHAR ig_fmtW[] = {'I','G','_','%','i',0};
61 static const WCHAR im_fmtW[] = {'I','M','_','%','i',0};
64 TRACE("PDO add device(%p)\n", PDO);
65 minidriver = find_minidriver(driver);
67 status = HID_CreateDevice(PDO, &minidriver->minidriver, &device);
68 if (status != STATUS_SUCCESS)
70 ERR("Failed to create HID object (%x)\n",status);
71 return status;
74 TRACE("Created device %p\n",device);
75 status = minidriver->AddDevice(minidriver->minidriver.DriverObject, device);
76 if (status != STATUS_SUCCESS)
78 ERR("Minidriver AddDevice failed (%x)\n",status);
79 HID_DeleteDevice(&minidriver->minidriver, device);
80 return status;
83 status = call_minidriver(IOCTL_HID_GET_DEVICE_ATTRIBUTES, device,
84 NULL, 0, &attr, sizeof(attr));
86 if (status != STATUS_SUCCESS)
88 ERR("Minidriver failed to get Attributes(%x)\n",status);
89 HID_DeleteDevice(&minidriver->minidriver, device);
90 return status;
93 ext = device->DeviceExtension;
94 ext->information.VendorID = attr.VendorID;
95 ext->information.ProductID = attr.ProductID;
96 ext->information.VersionNumber = attr.VersionNumber;
97 ext->information.Polled = minidriver->minidriver.DevicesArePolled;
99 tracked_device = HeapAlloc(GetProcessHeap(), 0, sizeof(*tracked_device));
100 tracked_device->vidpid = MAKELONG(attr.VendorID, attr.ProductID);
101 tracked_device->PDO = PDO;
102 tracked_device->FDO = device;
103 tracked_device->minidriver = &minidriver->minidriver;
105 LIST_FOR_EACH_ENTRY(ptr, &tracked_devices, NATIVE_DEVICE, entry)
106 if (ptr->vidpid == tracked_device->vidpid) interface_index++;
108 list_add_tail(&tracked_devices, &tracked_device->entry);
110 status = call_minidriver(IOCTL_HID_GET_DEVICE_DESCRIPTOR, device, NULL, 0,
111 &descriptor, sizeof(descriptor));
112 if (status != STATUS_SUCCESS)
114 ERR("Cannot get Device Descriptor(%x)\n",status);
115 HID_DeleteDevice(&minidriver->minidriver, device);
116 return status;
118 for (i = 0; i < descriptor.bNumDescriptors; i++)
119 if (descriptor.DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE)
120 break;
122 if (i >= descriptor.bNumDescriptors)
124 ERR("No Report Descriptor found in reply\n");
125 HID_DeleteDevice(&minidriver->minidriver, device);
126 return status;
129 reportDescriptor = HeapAlloc(GetProcessHeap(), 0, descriptor.DescriptorList[i].wReportLength);
130 status = call_minidriver(IOCTL_HID_GET_REPORT_DESCRIPTOR, device, NULL, 0,
131 reportDescriptor, descriptor.DescriptorList[i].wReportLength);
132 if (status != STATUS_SUCCESS)
134 ERR("Cannot get Report Descriptor(%x)\n",status);
135 HID_DeleteDevice(&minidriver->minidriver, device);
136 HeapFree(GetProcessHeap(), 0, reportDescriptor);
137 return status;
140 ext->preparseData = ParseDescriptor(reportDescriptor, descriptor.DescriptorList[0].wReportLength);
141 ext->information.DescriptorSize = ext->preparseData->dwSize;
142 HeapFree(GetProcessHeap(), 0, reportDescriptor);
144 serial[0] = 0;
145 status = call_minidriver(IOCTL_HID_GET_STRING, device,
146 &index, sizeof(DWORD), serial, sizeof(serial));
148 if (serial[0] == 0)
150 static const WCHAR wZeroSerial[]= {'0','0','0','0',0};
151 lstrcpyW(serial, wZeroSerial);
154 if (ext->preparseData->caps.UsagePage == HID_USAGE_PAGE_GENERIC &&
155 (ext->preparseData->caps.Usage == HID_USAGE_GENERIC_GAMEPAD ||
156 ext->preparseData->caps.Usage == HID_USAGE_GENERIC_JOYSTICK))
157 sprintfW(interface, ig_fmtW, interface_index);
158 else
159 sprintfW(interface, im_fmtW, interface_index);
161 HID_LinkDevice(device, serial, interface);
163 ext->poll_interval = DEFAULT_POLL_INTERVAL;
164 InitializeListHead(&ext->irp_queue);
166 ext->ring_buffer = RingBuffer_Create(sizeof(HID_XFER_PACKET) + ext->preparseData->caps.InputReportByteLength);
168 HID_StartDeviceThread(device);
170 return STATUS_SUCCESS;
173 void PNP_CleanupPNP(DRIVER_OBJECT *driver)
175 NATIVE_DEVICE *tracked_device, *ptr;
177 LIST_FOR_EACH_ENTRY_SAFE(tracked_device, ptr, &tracked_devices,
178 NATIVE_DEVICE, entry)
180 if (tracked_device->minidriver->DriverObject == driver)
182 list_remove(&tracked_device->entry);
183 HID_DeleteDevice(tracked_device->minidriver, tracked_device->FDO);
184 HeapFree(GetProcessHeap(), 0, tracked_device);