forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.2 KiB
113 lines
3.2 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* HID driver for Gembird Joypad, "PC Game Controller" |
|
* |
|
* Copyright (c) 2015 Red Hat, Inc |
|
* Copyright (c) 2015 Benjamin Tissoires |
|
*/ |
|
|
|
/* |
|
*/ |
|
|
|
#include <linux/device.h> |
|
#include <linux/hid.h> |
|
#include <linux/module.h> |
|
|
|
#include "hid-ids.h" |
|
|
|
#define GEMBIRD_START_FAULTY_RDESC 8 |
|
|
|
static const __u8 gembird_jpd_faulty_rdesc[] = { |
|
0x75, 0x08, /* Report Size (8) */ |
|
0x95, 0x05, /* Report Count (5) */ |
|
0x15, 0x00, /* Logical Minimum (0) */ |
|
0x26, 0xff, 0x00, /* Logical Maximum (255) */ |
|
0x35, 0x00, /* Physical Minimum (0) */ |
|
0x46, 0xff, 0x00, /* Physical Maximum (255) */ |
|
0x09, 0x30, /* Usage (X) */ |
|
0x09, 0x31, /* Usage (Y) */ |
|
0x09, 0x32, /* Usage (Z) */ |
|
0x09, 0x32, /* Usage (Z) */ |
|
0x09, 0x35, /* Usage (Rz) */ |
|
0x81, 0x02, /* Input (Data,Var,Abs) */ |
|
}; |
|
|
|
/* |
|
* we fix the report descriptor by: |
|
* - marking the first Z axis as constant (so it is ignored by HID) |
|
* - assign the original second Z to Rx |
|
* - assign the original Rz to Ry |
|
*/ |
|
static const __u8 gembird_jpd_fixed_rdesc[] = { |
|
0x75, 0x08, /* Report Size (8) */ |
|
0x95, 0x02, /* Report Count (2) */ |
|
0x15, 0x00, /* Logical Minimum (0) */ |
|
0x26, 0xff, 0x00, /* Logical Maximum (255) */ |
|
0x35, 0x00, /* Physical Minimum (0) */ |
|
0x46, 0xff, 0x00, /* Physical Maximum (255) */ |
|
0x09, 0x30, /* Usage (X) */ |
|
0x09, 0x31, /* Usage (Y) */ |
|
0x81, 0x02, /* Input (Data,Var,Abs) */ |
|
0x95, 0x01, /* Report Count (1) */ |
|
0x09, 0x32, /* Usage (Z) */ |
|
0x81, 0x01, /* Input (Cnst,Arr,Abs) */ |
|
0x95, 0x02, /* Report Count (2) */ |
|
0x09, 0x33, /* Usage (Rx) */ |
|
0x09, 0x34, /* Usage (Ry) */ |
|
0x81, 0x02, /* Input (Data,Var,Abs) */ |
|
}; |
|
|
|
static __u8 *gembird_report_fixup(struct hid_device *hdev, __u8 *rdesc, |
|
unsigned int *rsize) |
|
{ |
|
__u8 *new_rdesc; |
|
/* delta_size is > 0 */ |
|
size_t delta_size = sizeof(gembird_jpd_fixed_rdesc) - |
|
sizeof(gembird_jpd_faulty_rdesc); |
|
size_t new_size = *rsize + delta_size; |
|
|
|
if (*rsize >= 31 && !memcmp(&rdesc[GEMBIRD_START_FAULTY_RDESC], |
|
gembird_jpd_faulty_rdesc, |
|
sizeof(gembird_jpd_faulty_rdesc))) { |
|
new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL); |
|
if (new_rdesc == NULL) |
|
return rdesc; |
|
|
|
dev_info(&hdev->dev, |
|
"fixing Gembird JPD-DualForce 2 report descriptor.\n"); |
|
|
|
/* start by copying the end of the rdesc */ |
|
memcpy(new_rdesc + delta_size, rdesc, *rsize); |
|
|
|
/* add the correct beginning */ |
|
memcpy(new_rdesc, rdesc, GEMBIRD_START_FAULTY_RDESC); |
|
|
|
/* replace the faulty part with the fixed one */ |
|
memcpy(new_rdesc + GEMBIRD_START_FAULTY_RDESC, |
|
gembird_jpd_fixed_rdesc, |
|
sizeof(gembird_jpd_fixed_rdesc)); |
|
|
|
*rsize = new_size; |
|
rdesc = new_rdesc; |
|
} |
|
|
|
return rdesc; |
|
} |
|
|
|
static const struct hid_device_id gembird_devices[] = { |
|
{ HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD, |
|
USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) }, |
|
{ } |
|
}; |
|
MODULE_DEVICE_TABLE(hid, gembird_devices); |
|
|
|
static struct hid_driver gembird_driver = { |
|
.name = "gembird", |
|
.id_table = gembird_devices, |
|
.report_fixup = gembird_report_fixup, |
|
}; |
|
module_hid_driver(gembird_driver); |
|
|
|
MODULE_AUTHOR("Benjamin Tissoires <[email protected]>"); |
|
MODULE_DESCRIPTION("HID Gembird joypad driver"); |
|
MODULE_LICENSE("GPL");
|
|
|