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
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
{
38 HID_MINIDRIVER_REGISTRATION
*minidriver
;
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
;
48 minidriver
*minidriver
;
49 HID_DEVICE_ATTRIBUTES attr
;
50 BASE_DEVICE_EXTENSION
*ext
= NULL
;
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
;
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
);
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
);
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
);
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
);
118 for (i
= 0; i
< descriptor
.bNumDescriptors
; i
++)
119 if (descriptor
.DescriptorList
[i
].bReportType
== HID_REPORT_DESCRIPTOR_TYPE
)
122 if (i
>= descriptor
.bNumDescriptors
)
124 ERR("No Report Descriptor found in reply\n");
125 HID_DeleteDevice(&minidriver
->minidriver
, device
);
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
);
140 ext
->preparseData
= ParseDescriptor(reportDescriptor
, descriptor
.DescriptorList
[0].wReportLength
);
141 ext
->information
.DescriptorSize
= ext
->preparseData
->dwSize
;
142 HeapFree(GetProcessHeap(), 0, reportDescriptor
);
145 status
= call_minidriver(IOCTL_HID_GET_STRING
, device
,
146 &index
, sizeof(DWORD
), serial
, sizeof(serial
));
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
);
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
);