winebus.sys: Build SDL device report.

Signed-off-by: Aric Stewart <aric@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Aric Stewart 2018-02-21 06:56:31 -06:00 committed by Alexandre Julliard
parent 752de1b566
commit eda33b4b61
3 changed files with 312 additions and 95 deletions

View File

@ -45,6 +45,7 @@
#include "wine/debug.h"
#include "wine/unicode.h"
#include "hidusage.h"
#include "controller.h"
#ifdef WORDS_BIGENDIAN
# define LE_WORD(x) RtlUshortByteSwap(x)
@ -81,6 +82,9 @@ MAKE_FUNCPTR(SDL_JoystickName);
MAKE_FUNCPTR(SDL_JoystickNumAxes);
MAKE_FUNCPTR(SDL_JoystickOpen);
MAKE_FUNCPTR(SDL_WaitEvent);
MAKE_FUNCPTR(SDL_JoystickNumButtons);
MAKE_FUNCPTR(SDL_JoystickNumBalls);
MAKE_FUNCPTR(SDL_JoystickNumHats);
#endif
static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick);
static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick);
@ -90,6 +94,13 @@ struct platform_private
{
SDL_Joystick *sdl_joystick;
SDL_JoystickID id;
int axis_start;
int ball_start;
int hat_start;
int report_descriptor_size;
BYTE *report_descriptor;
};
static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
@ -97,6 +108,171 @@ static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *de
return (struct platform_private *)get_platform_private(device);
}
static const BYTE REPORT_AXIS_TAIL[] = {
0x16, 0x00, 0x80, /* LOGICAL_MINIMUM (-32768) */
0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (32767) */
0x36, 0x00, 0x80, /* PHYSICAL_MINIMUM (-32768) */
0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (32767) */
0x75, 0x10, /* REPORT_SIZE (16) */
0x95, 0x00, /* REPORT_COUNT (?) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
};
#define IDX_ABS_AXIS_COUNT 15
static BYTE *add_axis_block(BYTE *report_ptr, BYTE count, BYTE page, const BYTE *usages, BOOL absolute)
{
int i;
memcpy(report_ptr, REPORT_AXIS_HEADER, sizeof(REPORT_AXIS_HEADER));
report_ptr[IDX_AXIS_PAGE] = page;
report_ptr += sizeof(REPORT_AXIS_HEADER);
for (i = 0; i < count; i++)
{
memcpy(report_ptr, REPORT_AXIS_USAGE, sizeof(REPORT_AXIS_USAGE));
report_ptr[IDX_AXIS_USAGE] = usages[i];
report_ptr += sizeof(REPORT_AXIS_USAGE);
}
if (absolute)
{
memcpy(report_ptr, REPORT_AXIS_TAIL, sizeof(REPORT_AXIS_TAIL));
report_ptr[IDX_ABS_AXIS_COUNT] = count;
report_ptr += sizeof(REPORT_AXIS_TAIL);
}
else
{
memcpy(report_ptr, REPORT_REL_AXIS_TAIL, sizeof(REPORT_REL_AXIS_TAIL));
report_ptr[IDX_REL_AXIS_COUNT] = count;
report_ptr += sizeof(REPORT_REL_AXIS_TAIL);
}
return report_ptr;
}
static BOOL build_report_descriptor(struct platform_private *ext)
{
BYTE *report_ptr;
INT i, descript_size;
INT report_size;
INT button_count, axis_count, ball_count, hat_count;
static const BYTE device_usage[2] = {HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_GAMEPAD};
static const BYTE controller_usages[] = {
HID_USAGE_GENERIC_X,
HID_USAGE_GENERIC_Y,
HID_USAGE_GENERIC_Z,
HID_USAGE_GENERIC_RX,
HID_USAGE_GENERIC_RY,
HID_USAGE_GENERIC_RZ,
HID_USAGE_GENERIC_SLIDER,
HID_USAGE_GENERIC_DIAL,
HID_USAGE_GENERIC_WHEEL};
static const BYTE joystick_usages[] = {
HID_USAGE_GENERIC_X,
HID_USAGE_GENERIC_Y,
HID_USAGE_GENERIC_Z,
HID_USAGE_GENERIC_RZ,
HID_USAGE_GENERIC_RX,
HID_USAGE_GENERIC_RY,
HID_USAGE_GENERIC_SLIDER,
HID_USAGE_GENERIC_DIAL,
HID_USAGE_GENERIC_WHEEL};
descript_size = sizeof(REPORT_HEADER) + sizeof(REPORT_TAIL);
report_size = 0;
/* For now lump all buttons just into incremental usages, Ignore Keys */
button_count = pSDL_JoystickNumButtons(ext->sdl_joystick);
if (button_count)
{
descript_size += sizeof(REPORT_BUTTONS);
if (button_count % 8)
descript_size += sizeof(REPORT_PADDING);
report_size = (button_count + 7) / 8;
}
axis_count = pSDL_JoystickNumAxes(ext->sdl_joystick);
if (axis_count > 6)
{
FIXME("Clamping joystick to 6 axis\n");
axis_count = 6;
}
ext->axis_start = report_size;
if (axis_count)
{
descript_size += sizeof(REPORT_AXIS_HEADER);
descript_size += (sizeof(REPORT_AXIS_USAGE) * axis_count);
descript_size += sizeof(REPORT_AXIS_TAIL);
report_size += (2 * axis_count);
}
ball_count = pSDL_JoystickNumBalls(ext->sdl_joystick);
ext->ball_start = report_size;
if (ball_count)
{
if ((ball_count*2) + axis_count > 9)
{
FIXME("Capping ball + axis at 9\n");
ball_count = (9-axis_count)/2;
}
descript_size += sizeof(REPORT_AXIS_HEADER);
descript_size += (sizeof(REPORT_AXIS_USAGE) * ball_count * 2);
descript_size += sizeof(REPORT_REL_AXIS_TAIL);
report_size += (2*ball_count);
}
hat_count = pSDL_JoystickNumHats(ext->sdl_joystick);
ext->hat_start = report_size;
if (hat_count)
{
descript_size += sizeof(REPORT_HATSWITCH);
for (i = 0; i < hat_count; i++)
report_size++;
}
TRACE("Report Descriptor will be %i bytes\n", descript_size);
TRACE("Report will be %i bytes\n", report_size);
ext->report_descriptor = HeapAlloc(GetProcessHeap(), 0, descript_size);
if (!ext->report_descriptor)
{
ERR("Failed to alloc report descriptor\n");
return FALSE;
}
report_ptr = ext->report_descriptor;
memcpy(report_ptr, REPORT_HEADER, sizeof(REPORT_HEADER));
report_ptr[IDX_HEADER_PAGE] = device_usage[0];
report_ptr[IDX_HEADER_USAGE] = device_usage[1];
report_ptr += sizeof(REPORT_HEADER);
if (button_count)
{
report_ptr = add_button_block(report_ptr, 1, button_count);
if (button_count % 8)
{
BYTE padding = 8 - (button_count % 8);
report_ptr = add_padding_block(report_ptr, padding);
}
}
if (axis_count)
{
if (axis_count == 6 && button_count >= 14)
report_ptr = add_axis_block(report_ptr, axis_count, HID_USAGE_PAGE_GENERIC, controller_usages, TRUE);
else
report_ptr = add_axis_block(report_ptr, axis_count, HID_USAGE_PAGE_GENERIC, joystick_usages, TRUE);
}
if (ball_count)
{
report_ptr = add_axis_block(report_ptr, ball_count * 2, HID_USAGE_PAGE_GENERIC, &joystick_usages[axis_count], FALSE);
}
if (hat_count)
report_ptr = add_hatswitch(report_ptr, hat_count);
memcpy(report_ptr, REPORT_TAIL, sizeof(REPORT_TAIL));
ext->report_descriptor_size = descript_size;
return TRUE;
}
static int compare_platform_device(DEVICE_OBJECT *device, void *platform_dev)
{
SDL_JoystickID id1 = impl_from_DEVICE_OBJECT(device)->id;
@ -106,7 +282,16 @@ static int compare_platform_device(DEVICE_OBJECT *device, void *platform_dev)
static NTSTATUS get_reportdescriptor(DEVICE_OBJECT *device, BYTE *buffer, DWORD length, DWORD *out_length)
{
return STATUS_NOT_IMPLEMENTED;
struct platform_private *ext = impl_from_DEVICE_OBJECT(device);
*out_length = ext->report_descriptor_size;
if (length < ext->report_descriptor_size)
return STATUS_BUFFER_TOO_SMALL;
memcpy(buffer, ext->report_descriptor, ext->report_descriptor_size);
return STATUS_SUCCESS;
}
static NTSTATUS get_string(DEVICE_OBJECT *device, DWORD index, WCHAR *buffer, DWORD length)
@ -233,6 +418,13 @@ static void try_add_device(SDL_JoystickID index)
struct platform_private *private = impl_from_DEVICE_OBJECT(device);
private->sdl_joystick = joystick;
private->id = id;
if (!build_report_descriptor(private))
{
ERR("Building report descriptor failed, removing device\n");
bus_remove_hid_device(device);
HeapFree(GetProcessHeap(), 0, serial);
return;
}
IoInvalidateDeviceRelations(device, BusRelations);
}
else
@ -299,6 +491,9 @@ NTSTATUS WINAPI sdl_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_
LOAD_FUNCPTR(SDL_JoystickNumAxes);
LOAD_FUNCPTR(SDL_JoystickOpen);
LOAD_FUNCPTR(SDL_WaitEvent);
LOAD_FUNCPTR(SDL_JoystickNumButtons);
LOAD_FUNCPTR(SDL_JoystickNumBalls);
LOAD_FUNCPTR(SDL_JoystickNumHats);
#undef LOAD_FUNCPTR
pSDL_JoystickGetProduct = wine_dlsym(sdl_handle, "SDL_JoystickGetProduct", NULL, 0);
pSDL_JoystickGetProductVersion = wine_dlsym(sdl_handle, "SDL_JoystickGetProductVersion", NULL, 0);

View File

@ -75,6 +75,7 @@
#define LE_DWORD(x) (x)
#endif
#include "controller.h"
#include "bus.h"
WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
@ -110,50 +111,6 @@ static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *de
}
#ifdef HAS_PROPER_INPUT_HEADER
static const BYTE REPORT_HEADER[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x00, /* USAGE (??) */
0xa1, 0x01, /* COLLECTION (Application) */
0x09, 0x01, /* USAGE () */
0xa1, 0x00, /* COLLECTION (Physical) */
};
#define IDX_HEADER_PAGE 1
#define IDX_HEADER_USAGE 3
static const BYTE REPORT_BUTTONS[] = {
0x05, 0x09, /* USAGE_PAGE (Button) */
0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x35, 0x00, /* LOGICAL_MINIMUM (0) */
0x45, 0x01, /* LOGICAL_MAXIMUM (1) */
0x95, 0x03, /* REPORT_COUNT (3) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
};
#define IDX_BUTTON_MIN_USAGE 3
#define IDX_BUTTON_MAX_USAGE 5
#define IDX_BUTTON_COUNT 11
static const BYTE REPORT_PADDING[] = {
0x95, 0x03, /* REPORT_COUNT (3) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
};
#define IDX_PADDING_BIT_COUNT 1
static const BYTE REPORT_AXIS_HEADER[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
};
#define IDX_AXIS_PAGE 1
static const BYTE REPORT_AXIS_USAGE[] = {
0x09, 0x30, /* USAGE (X) */
};
#define IDX_AXIS_USAGE 1
static const BYTE REPORT_ABS_AXIS_TAIL[] = {
0x17, 0x00, 0x00, 0x00, 0x00, /* LOGICAL_MINIMUM (0) */
@ -170,33 +127,6 @@ static const BYTE REPORT_ABS_AXIS_TAIL[] = {
#define IDX_ABS_PHY_MAXIMUM 16
#define IDX_ABS_AXIS_COUNT 23
static const BYTE REPORT_REL_AXIS_TAIL[] = {
0x15, 0x81, /* LOGICAL_MINIMUM (0) */
0x25, 0x7f, /* LOGICAL_MAXIMUM (0xffff) */
0x75, 0x08, /* REPORT_SIZE (16) */
0x95, 0x02, /* REPORT_COUNT (2) */
0x81, 0x06, /* INPUT (Data,Var,Rel) */
};
#define IDX_REL_AXIS_COUNT 7
static const BYTE REPORT_HATSWITCH[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x39, /* USAGE (Hatswitch) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x08, /* LOGICAL_MAXIMUM (0x08) */
0x35, 0x00, /* PHYSICAL_MINIMUM (0) */
0x45, 0x08, /* PHYSICAL_MAXIMUM (8) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
};
#define IDX_HATSWITCH_COUNT 15
static const BYTE REPORT_TAIL[] = {
0xc0, /* END_COLLECTION */
0xc0 /* END_COLLECTION */
};
static const BYTE ABS_TO_HID_MAP[][2] = {
{HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X}, /*ABS_X*/
{HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_Y}, /*ABS_Y*/
@ -271,15 +201,6 @@ struct wine_input_private {
#define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
static BYTE *add_button_block(BYTE* report_ptr, BYTE usage_min, BYTE usage_max)
{
memcpy(report_ptr, REPORT_BUTTONS, sizeof(REPORT_BUTTONS));
report_ptr[IDX_BUTTON_MIN_USAGE] = usage_min;
report_ptr[IDX_BUTTON_MAX_USAGE] = usage_max;
report_ptr[IDX_BUTTON_COUNT] = (usage_max - usage_min) + 1;
return report_ptr + sizeof(REPORT_BUTTONS);
}
static BYTE *add_axis_block(BYTE *report_ptr, BYTE count, BYTE page, BYTE *usages, BOOL absolute, const struct wine_input_absinfo *absinfo)
{
int i;
@ -314,20 +235,6 @@ static BYTE *add_axis_block(BYTE *report_ptr, BYTE count, BYTE page, BYTE *usage
return report_ptr;
}
static BYTE *add_padding_block(BYTE *report_ptr, BYTE bitcount)
{
memcpy(report_ptr, REPORT_PADDING, sizeof(REPORT_PADDING));
report_ptr[IDX_PADDING_BIT_COUNT] = bitcount;
return report_ptr + sizeof(REPORT_PADDING);
}
static BYTE *add_hatswitch(BYTE *report_ptr, INT count)
{
memcpy(report_ptr, REPORT_HATSWITCH, sizeof(REPORT_HATSWITCH));
report_ptr[IDX_HATSWITCH_COUNT] = count;
return report_ptr + sizeof(REPORT_HATSWITCH);
}
static const BYTE* what_am_I(struct udev_device *dev)
{
static const BYTE Unknown[2] = {HID_USAGE_PAGE_GENERIC, 0};

View File

@ -0,0 +1,115 @@
/*
* Common controller functions and structures
*
* Copyright 2018 Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* Blocks of data for building HID device descriptions */
static const BYTE REPORT_HEADER[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x00, /* USAGE (??) */
0xa1, 0x01, /* COLLECTION (Application) */
0x09, 0x01, /* USAGE () */
0xa1, 0x00, /* COLLECTION (Physical) */
};
#define IDX_HEADER_PAGE 1
#define IDX_HEADER_USAGE 3
static const BYTE REPORT_BUTTONS[] = {
0x05, 0x09, /* USAGE_PAGE (Button) */
0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x35, 0x00, /* LOGICAL_MINIMUM (0) */
0x45, 0x01, /* LOGICAL_MAXIMUM (1) */
0x95, 0x03, /* REPORT_COUNT (3) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
};
#define IDX_BUTTON_MIN_USAGE 3
#define IDX_BUTTON_MAX_USAGE 5
#define IDX_BUTTON_COUNT 11
static const BYTE REPORT_PADDING[] = {
0x95, 0x03, /* REPORT_COUNT (3) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
};
#define IDX_PADDING_BIT_COUNT 1
static const BYTE REPORT_AXIS_HEADER[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
};
#define IDX_AXIS_PAGE 1
static const BYTE REPORT_AXIS_USAGE[] = {
0x09, 0x30, /* USAGE (X) */
};
#define IDX_AXIS_USAGE 1
static const BYTE REPORT_REL_AXIS_TAIL[] = {
0x15, 0x81, /* LOGICAL_MINIMUM (0) */
0x25, 0x7f, /* LOGICAL_MAXIMUM (0xffff) */
0x75, 0x08, /* REPORT_SIZE (16) */
0x95, 0x02, /* REPORT_COUNT (2) */
0x81, 0x06, /* INPUT (Data,Var,Rel) */
};
#define IDX_REL_AXIS_COUNT 7
static const BYTE REPORT_HATSWITCH[] = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x39, /* USAGE (Hatswitch) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x08, /* LOGICAL_MAXIMUM (0x08) */
0x35, 0x00, /* PHYSICAL_MINIMUM (0) */
0x45, 0x08, /* PHYSICAL_MAXIMUM (8) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
};
#define IDX_HATSWITCH_COUNT 15
static const BYTE REPORT_TAIL[] = {
0xc0, /* END_COLLECTION */
0xc0 /* END_COLLECTION */
};
static inline BYTE *add_button_block(BYTE* report_ptr, BYTE usage_min, BYTE usage_max)
{
memcpy(report_ptr, REPORT_BUTTONS, sizeof(REPORT_BUTTONS));
report_ptr[IDX_BUTTON_MIN_USAGE] = usage_min;
report_ptr[IDX_BUTTON_MAX_USAGE] = usage_max;
report_ptr[IDX_BUTTON_COUNT] = (usage_max - usage_min) + 1;
return report_ptr + sizeof(REPORT_BUTTONS);
}
static inline BYTE *add_padding_block(BYTE *report_ptr, BYTE bitcount)
{
memcpy(report_ptr, REPORT_PADDING, sizeof(REPORT_PADDING));
report_ptr[IDX_PADDING_BIT_COUNT] = bitcount;
return report_ptr + sizeof(REPORT_PADDING);
}
static inline BYTE *add_hatswitch(BYTE *report_ptr, INT count)
{
memcpy(report_ptr, REPORT_HATSWITCH, sizeof(REPORT_HATSWITCH));
report_ptr[IDX_HATSWITCH_COUNT] = count;
return report_ptr + sizeof(REPORT_HATSWITCH);
}