2 * Copyright 2021 RĂ©mi Bernon for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #define WIN32_NO_STATUS
33 #include "ddk/hidtypes.h"
35 #include "wine/debug.h"
36 #include "wine/list.h"
37 #include "wine/unixlib.h"
39 #include "unix_private.h"
41 BOOL
is_xbox_gamepad(WORD vid
, WORD pid
)
43 if (vid
!= 0x045e) return FALSE
;
44 if (pid
== 0x0202) return TRUE
; /* Xbox Controller */
45 if (pid
== 0x0285) return TRUE
; /* Xbox Controller S */
46 if (pid
== 0x0289) return TRUE
; /* Xbox Controller S */
47 if (pid
== 0x028e) return TRUE
; /* Xbox360 Controller */
48 if (pid
== 0x028f) return TRUE
; /* Xbox360 Wireless Controller */
49 if (pid
== 0x02d1) return TRUE
; /* Xbox One Controller */
50 if (pid
== 0x02dd) return TRUE
; /* Xbox One Controller (Covert Forces/Firmware 2015) */
51 if (pid
== 0x02e0) return TRUE
; /* Xbox One X Controller */
52 if (pid
== 0x02e3) return TRUE
; /* Xbox One Elite Controller */
53 if (pid
== 0x02e6) return TRUE
; /* Wireless XBox Controller Dongle */
54 if (pid
== 0x02ea) return TRUE
; /* Xbox One S Controller */
55 if (pid
== 0x02fd) return TRUE
; /* Xbox One S Controller (Firmware 2017) */
56 if (pid
== 0x0b00) return TRUE
; /* Xbox Elite 2 */
57 if (pid
== 0x0b05) return TRUE
; /* Xbox Elite 2 Wireless */
58 if (pid
== 0x0b12) return TRUE
; /* Xbox Series */
59 if (pid
== 0x0b13) return TRUE
; /* Xbox Series Wireless */
60 if (pid
== 0x0719) return TRUE
; /* Xbox 360 Wireless Adapter */
64 BOOL
is_dualshock4_gamepad(WORD vid
, WORD pid
)
66 if (vid
!= 0x054c) return FALSE
;
67 if (pid
== 0x05c4) return TRUE
; /* DualShock 4 [CUH-ZCT1x] */
68 if (pid
== 0x09cc) return TRUE
; /* DualShock 4 [CUH-ZCT2x] */
69 if (pid
== 0x0ba0) return TRUE
; /* Dualshock 4 Wireless Adaptor */
73 BOOL
is_dualsense_gamepad(WORD vid
, WORD pid
)
75 if (vid
== 0x054c && pid
== 0x0ce6) return TRUE
;
81 struct unix_device unix_device
;
84 static void mouse_destroy(struct unix_device
*iface
)
88 static NTSTATUS
mouse_start(struct unix_device
*iface
)
90 const USAGE_AND_PAGE device_usage
= {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_MOUSE
};
91 if (!hid_device_begin_report_descriptor(iface
, &device_usage
))
92 return STATUS_NO_MEMORY
;
93 if (!hid_device_add_buttons(iface
, HID_USAGE_PAGE_BUTTON
, 1, 3))
94 return STATUS_NO_MEMORY
;
95 if (!hid_device_end_report_descriptor(iface
))
96 return STATUS_NO_MEMORY
;
98 return STATUS_SUCCESS
;
101 static void mouse_stop(struct unix_device
*iface
)
105 static NTSTATUS
mouse_haptics_start(struct unix_device
*iface
, UINT duration
,
106 USHORT rumble_intensity
, USHORT buzz_intensity
,
107 USHORT left_intensity
, USHORT right_intensity
)
109 return STATUS_NOT_SUPPORTED
;
112 static NTSTATUS
mouse_haptics_stop(struct unix_device
*iface
)
114 return STATUS_NOT_SUPPORTED
;
117 static NTSTATUS
mouse_physical_device_control(struct unix_device
*iface
, USAGE control
)
119 return STATUS_NOT_SUPPORTED
;
122 static NTSTATUS
mouse_physical_device_set_gain(struct unix_device
*iface
, BYTE percent
)
124 return STATUS_NOT_SUPPORTED
;
127 static NTSTATUS
mouse_physical_effect_control(struct unix_device
*iface
, BYTE index
,
128 USAGE control
, BYTE iterations
)
130 return STATUS_NOT_SUPPORTED
;
133 static NTSTATUS
mouse_physical_effect_update(struct unix_device
*iface
, BYTE index
,
134 struct effect_params
*params
)
136 return STATUS_NOT_SUPPORTED
;
139 static const struct hid_device_vtbl mouse_vtbl
=
146 mouse_physical_device_control
,
147 mouse_physical_device_set_gain
,
148 mouse_physical_effect_control
,
149 mouse_physical_effect_update
,
152 static const struct device_desc mouse_device_desc
=
157 .manufacturer
= {'T','h','e',' ','W','i','n','e',' ','P','r','o','j','e','c','t',0},
158 .product
= {'W','i','n','e',' ','H','I','D',' ','m','o','u','s','e',0},
159 .serialnumber
= {'0','0','0','0',0},
162 static NTSTATUS
mouse_device_create(void *args
)
164 struct device_create_params
*params
= args
;
165 params
->desc
= mouse_device_desc
;
166 params
->device
= (UINT_PTR
)hid_device_create(&mouse_vtbl
, sizeof(struct mouse_device
));
167 return STATUS_SUCCESS
;
170 struct keyboard_device
172 struct unix_device unix_device
;
175 static void keyboard_destroy(struct unix_device
*iface
)
179 static NTSTATUS
keyboard_start(struct unix_device
*iface
)
181 const USAGE_AND_PAGE device_usage
= {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_KEYBOARD
};
182 if (!hid_device_begin_report_descriptor(iface
, &device_usage
))
183 return STATUS_NO_MEMORY
;
184 if (!hid_device_add_buttons(iface
, HID_USAGE_PAGE_KEYBOARD
, 0, 101))
185 return STATUS_NO_MEMORY
;
186 if (!hid_device_end_report_descriptor(iface
))
187 return STATUS_NO_MEMORY
;
189 return STATUS_SUCCESS
;
192 static void keyboard_stop(struct unix_device
*iface
)
196 static NTSTATUS
keyboard_haptics_start(struct unix_device
*iface
, UINT duration
,
197 USHORT rumble_intensity
, USHORT buzz_intensity
,
198 USHORT left_intensity
, USHORT right_intensity
)
200 return STATUS_NOT_SUPPORTED
;
203 static NTSTATUS
keyboard_haptics_stop(struct unix_device
*iface
)
205 return STATUS_NOT_SUPPORTED
;
208 static NTSTATUS
keyboard_physical_device_control(struct unix_device
*iface
, USAGE control
)
210 return STATUS_NOT_SUPPORTED
;
213 static NTSTATUS
keyboard_physical_device_set_gain(struct unix_device
*iface
, BYTE percent
)
215 return STATUS_NOT_SUPPORTED
;
218 static NTSTATUS
keyboard_physical_effect_control(struct unix_device
*iface
, BYTE index
,
219 USAGE control
, BYTE iterations
)
221 return STATUS_NOT_SUPPORTED
;
224 static NTSTATUS
keyboard_physical_effect_update(struct unix_device
*iface
, BYTE index
,
225 struct effect_params
*params
)
227 return STATUS_NOT_SUPPORTED
;
230 static const struct hid_device_vtbl keyboard_vtbl
=
235 keyboard_haptics_start
,
236 keyboard_haptics_stop
,
237 keyboard_physical_device_control
,
238 keyboard_physical_device_set_gain
,
239 keyboard_physical_effect_control
,
240 keyboard_physical_effect_update
,
243 static const struct device_desc keyboard_device_desc
=
248 .manufacturer
= {'T','h','e',' ','W','i','n','e',' ','P','r','o','j','e','c','t',0},
249 .product
= {'W','i','n','e',' ','H','I','D',' ','k','e','y','b','o','a','r','d',0},
250 .serialnumber
= {'0','0','0','0',0},
253 static NTSTATUS
keyboard_device_create(void *args
)
255 struct device_create_params
*params
= args
;
256 params
->desc
= keyboard_device_desc
;
257 params
->device
= (UINT_PTR
)hid_device_create(&keyboard_vtbl
, sizeof(struct keyboard_device
));
258 return STATUS_SUCCESS
;
261 void *raw_device_create(const struct raw_device_vtbl
*vtbl
, SIZE_T size
)
263 struct unix_device
*iface
;
265 if (!(iface
= calloc(1, size
))) return NULL
;
272 static void unix_device_decref(struct unix_device
*iface
)
274 if (!InterlockedDecrement(&iface
->ref
))
276 iface
->vtbl
->destroy(iface
);
281 static ULONG
unix_device_incref(struct unix_device
*iface
)
283 return InterlockedIncrement(&iface
->ref
);
286 static NTSTATUS
unix_device_remove(void *args
)
288 struct device_remove_params
*params
= args
;
289 struct unix_device
*iface
= (struct unix_device
*)(UINT_PTR
)params
->device
;
290 iface
->vtbl
->stop(iface
);
291 unix_device_decref(iface
);
292 return STATUS_SUCCESS
;
295 static NTSTATUS
unix_device_start(void *args
)
297 struct device_start_params
*params
= args
;
298 struct unix_device
*iface
= (struct unix_device
*)(UINT_PTR
)params
->device
;
299 return iface
->vtbl
->start(iface
);
302 static NTSTATUS
unix_device_get_report_descriptor(void *args
)
304 struct device_descriptor_params
*params
= args
;
305 struct unix_device
*iface
= (struct unix_device
*)(UINT_PTR
)params
->device
;
306 return iface
->vtbl
->get_report_descriptor(iface
, params
->buffer
, params
->length
, params
->out_length
);
309 static NTSTATUS
unix_device_set_output_report(void *args
)
311 struct device_report_params
*params
= args
;
312 struct unix_device
*iface
= (struct unix_device
*)(UINT_PTR
)params
->device
;
313 iface
->vtbl
->set_output_report(iface
, params
->packet
, params
->io
);
314 return STATUS_SUCCESS
;
317 static NTSTATUS
unix_device_get_feature_report(void *args
)
319 struct device_report_params
*params
= args
;
320 struct unix_device
*iface
= (struct unix_device
*)(UINT_PTR
)params
->device
;
321 iface
->vtbl
->get_feature_report(iface
, params
->packet
, params
->io
);
322 return STATUS_SUCCESS
;
325 static NTSTATUS
unix_device_set_feature_report(void *args
)
327 struct device_report_params
*params
= args
;
328 struct unix_device
*iface
= (struct unix_device
*)(UINT_PTR
)params
->device
;
329 iface
->vtbl
->set_feature_report(iface
, params
->packet
, params
->io
);
330 return STATUS_SUCCESS
;
333 const unixlib_entry_t __wine_unix_call_funcs
[] =
345 keyboard_device_create
,
348 unix_device_get_report_descriptor
,
349 unix_device_set_output_report
,
350 unix_device_get_feature_report
,
351 unix_device_set_feature_report
,
354 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs
) == unix_funcs_count
);
356 void bus_event_cleanup(struct bus_event
*event
)
358 struct unix_device
*iface
= (struct unix_device
*)(UINT_PTR
)event
->device
;
359 if (event
->type
== BUS_EVENT_TYPE_NONE
) return;
360 unix_device_decref(iface
);
363 struct bus_event_entry
366 struct bus_event event
;
369 void bus_event_queue_destroy(struct list
*queue
)
371 struct bus_event_entry
*entry
, *next
;
373 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, queue
, struct bus_event_entry
, entry
)
375 bus_event_cleanup(&entry
->event
);
376 list_remove(&entry
->entry
);
381 BOOL
bus_event_queue_device_removed(struct list
*queue
, struct unix_device
*device
)
383 ULONG size
= sizeof(struct bus_event_entry
);
384 struct bus_event_entry
*entry
= malloc(size
);
385 if (!entry
) return FALSE
;
387 if (unix_device_incref(device
) == 1) /* being destroyed */
393 entry
->event
.type
= BUS_EVENT_TYPE_DEVICE_REMOVED
;
394 entry
->event
.device
= (UINT_PTR
)device
;
395 list_add_tail(queue
, &entry
->entry
);
400 BOOL
bus_event_queue_device_created(struct list
*queue
, struct unix_device
*device
, struct device_desc
*desc
)
402 ULONG size
= sizeof(struct bus_event_entry
);
403 struct bus_event_entry
*entry
= malloc(size
);
404 if (!entry
) return FALSE
;
406 if (unix_device_incref(device
) == 1) /* being destroyed */
412 entry
->event
.type
= BUS_EVENT_TYPE_DEVICE_CREATED
;
413 entry
->event
.device
= (UINT_PTR
)device
;
414 entry
->event
.device_created
.desc
= *desc
;
415 list_add_tail(queue
, &entry
->entry
);
420 BOOL
bus_event_queue_input_report(struct list
*queue
, struct unix_device
*device
, BYTE
*report
, USHORT length
)
422 ULONG size
= offsetof(struct bus_event_entry
, event
.input_report
.buffer
[length
]);
423 struct bus_event_entry
*entry
= malloc(size
);
424 if (!entry
) return FALSE
;
426 if (unix_device_incref(device
) == 1) /* being destroyed */
432 entry
->event
.type
= BUS_EVENT_TYPE_INPUT_REPORT
;
433 entry
->event
.device
= (UINT_PTR
)device
;
434 entry
->event
.input_report
.length
= length
;
435 memcpy(entry
->event
.input_report
.buffer
, report
, length
);
436 list_add_tail(queue
, &entry
->entry
);
441 BOOL
bus_event_queue_pop(struct list
*queue
, struct bus_event
*event
)
443 struct list
*head
= list_head(queue
);
444 struct bus_event_entry
*entry
;
447 if (!head
) return FALSE
;
449 entry
= LIST_ENTRY(head
, struct bus_event_entry
, entry
);
450 list_remove(&entry
->entry
);
452 if (entry
->event
.type
!= BUS_EVENT_TYPE_INPUT_REPORT
) size
= sizeof(entry
->event
);
453 else size
= offsetof(struct bus_event
, input_report
.buffer
[entry
->event
.input_report
.length
]);
455 memcpy(event
, &entry
->event
, size
);