hid-gembird.c (3318B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * HID driver for Gembird Joypad, "PC Game Controller" 4 * 5 * Copyright (c) 2015 Red Hat, Inc 6 * Copyright (c) 2015 Benjamin Tissoires 7 */ 8 9/* 10 */ 11 12#include <linux/device.h> 13#include <linux/hid.h> 14#include <linux/module.h> 15 16#include "hid-ids.h" 17 18#define GEMBIRD_START_FAULTY_RDESC 8 19 20static const __u8 gembird_jpd_faulty_rdesc[] = { 21 0x75, 0x08, /* Report Size (8) */ 22 0x95, 0x05, /* Report Count (5) */ 23 0x15, 0x00, /* Logical Minimum (0) */ 24 0x26, 0xff, 0x00, /* Logical Maximum (255) */ 25 0x35, 0x00, /* Physical Minimum (0) */ 26 0x46, 0xff, 0x00, /* Physical Maximum (255) */ 27 0x09, 0x30, /* Usage (X) */ 28 0x09, 0x31, /* Usage (Y) */ 29 0x09, 0x32, /* Usage (Z) */ 30 0x09, 0x32, /* Usage (Z) */ 31 0x09, 0x35, /* Usage (Rz) */ 32 0x81, 0x02, /* Input (Data,Var,Abs) */ 33}; 34 35/* 36 * we fix the report descriptor by: 37 * - marking the first Z axis as constant (so it is ignored by HID) 38 * - assign the original second Z to Rx 39 * - assign the original Rz to Ry 40 */ 41static const __u8 gembird_jpd_fixed_rdesc[] = { 42 0x75, 0x08, /* Report Size (8) */ 43 0x95, 0x02, /* Report Count (2) */ 44 0x15, 0x00, /* Logical Minimum (0) */ 45 0x26, 0xff, 0x00, /* Logical Maximum (255) */ 46 0x35, 0x00, /* Physical Minimum (0) */ 47 0x46, 0xff, 0x00, /* Physical Maximum (255) */ 48 0x09, 0x30, /* Usage (X) */ 49 0x09, 0x31, /* Usage (Y) */ 50 0x81, 0x02, /* Input (Data,Var,Abs) */ 51 0x95, 0x01, /* Report Count (1) */ 52 0x09, 0x32, /* Usage (Z) */ 53 0x81, 0x01, /* Input (Cnst,Arr,Abs) */ 54 0x95, 0x02, /* Report Count (2) */ 55 0x09, 0x33, /* Usage (Rx) */ 56 0x09, 0x34, /* Usage (Ry) */ 57 0x81, 0x02, /* Input (Data,Var,Abs) */ 58}; 59 60static __u8 *gembird_report_fixup(struct hid_device *hdev, __u8 *rdesc, 61 unsigned int *rsize) 62{ 63 __u8 *new_rdesc; 64 /* delta_size is > 0 */ 65 size_t delta_size = sizeof(gembird_jpd_fixed_rdesc) - 66 sizeof(gembird_jpd_faulty_rdesc); 67 size_t new_size = *rsize + delta_size; 68 69 if (*rsize >= 31 && !memcmp(&rdesc[GEMBIRD_START_FAULTY_RDESC], 70 gembird_jpd_faulty_rdesc, 71 sizeof(gembird_jpd_faulty_rdesc))) { 72 new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL); 73 if (new_rdesc == NULL) 74 return rdesc; 75 76 dev_info(&hdev->dev, 77 "fixing Gembird JPD-DualForce 2 report descriptor.\n"); 78 79 /* start by copying the end of the rdesc */ 80 memcpy(new_rdesc + delta_size, rdesc, *rsize); 81 82 /* add the correct beginning */ 83 memcpy(new_rdesc, rdesc, GEMBIRD_START_FAULTY_RDESC); 84 85 /* replace the faulty part with the fixed one */ 86 memcpy(new_rdesc + GEMBIRD_START_FAULTY_RDESC, 87 gembird_jpd_fixed_rdesc, 88 sizeof(gembird_jpd_fixed_rdesc)); 89 90 *rsize = new_size; 91 rdesc = new_rdesc; 92 } 93 94 return rdesc; 95} 96 97static const struct hid_device_id gembird_devices[] = { 98 { HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD, 99 USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) }, 100 { } 101}; 102MODULE_DEVICE_TABLE(hid, gembird_devices); 103 104static struct hid_driver gembird_driver = { 105 .name = "gembird", 106 .id_table = gembird_devices, 107 .report_fixup = gembird_report_fixup, 108}; 109module_hid_driver(gembird_driver); 110 111MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 112MODULE_DESCRIPTION("HID Gembird joypad driver"); 113MODULE_LICENSE("GPL");