Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  HID driver for Gembird Joypad, "PC Game Controller"
0004  *
0005  *  Copyright (c) 2015 Red Hat, Inc
0006  *  Copyright (c) 2015 Benjamin Tissoires
0007  */
0008 
0009 /*
0010  */
0011 
0012 #include <linux/device.h>
0013 #include <linux/hid.h>
0014 #include <linux/module.h>
0015 
0016 #include "hid-ids.h"
0017 
0018 #define GEMBIRD_START_FAULTY_RDESC  8
0019 
0020 static const __u8 gembird_jpd_faulty_rdesc[] = {
0021     0x75, 0x08,         /*   Report Size (8)        */
0022     0x95, 0x05,         /*   Report Count (5)       */
0023     0x15, 0x00,         /*   Logical Minimum (0)    */
0024     0x26, 0xff, 0x00,       /*   Logical Maximum (255)  */
0025     0x35, 0x00,         /*   Physical Minimum (0)   */
0026     0x46, 0xff, 0x00,       /*   Physical Maximum (255) */
0027     0x09, 0x30,         /*   Usage (X)          */
0028     0x09, 0x31,         /*   Usage (Y)          */
0029     0x09, 0x32,         /*   Usage (Z)          */
0030     0x09, 0x32,         /*   Usage (Z)          */
0031     0x09, 0x35,         /*   Usage (Rz)         */
0032     0x81, 0x02,         /*   Input (Data,Var,Abs)   */
0033 };
0034 
0035 /*
0036  * we fix the report descriptor by:
0037  * - marking the first Z axis as constant (so it is ignored by HID)
0038  * - assign the original second Z to Rx
0039  * - assign the original Rz to Ry
0040  */
0041 static const __u8 gembird_jpd_fixed_rdesc[] = {
0042     0x75, 0x08,         /*   Report Size (8)        */
0043     0x95, 0x02,         /*   Report Count (2)       */
0044     0x15, 0x00,         /*   Logical Minimum (0)    */
0045     0x26, 0xff, 0x00,       /*   Logical Maximum (255)  */
0046     0x35, 0x00,         /*   Physical Minimum (0)   */
0047     0x46, 0xff, 0x00,       /*   Physical Maximum (255) */
0048     0x09, 0x30,         /*   Usage (X)          */
0049     0x09, 0x31,         /*   Usage (Y)          */
0050     0x81, 0x02,         /*   Input (Data,Var,Abs)   */
0051     0x95, 0x01,         /*   Report Count (1)       */
0052     0x09, 0x32,         /*   Usage (Z)          */
0053     0x81, 0x01,         /*   Input (Cnst,Arr,Abs)   */
0054     0x95, 0x02,         /*   Report Count (2)       */
0055     0x09, 0x33,         /*   Usage (Rx)         */
0056     0x09, 0x34,         /*   Usage (Ry)         */
0057     0x81, 0x02,         /*   Input (Data,Var,Abs)   */
0058 };
0059 
0060 static __u8 *gembird_report_fixup(struct hid_device *hdev, __u8 *rdesc,
0061         unsigned int *rsize)
0062 {
0063     __u8 *new_rdesc;
0064     /* delta_size is > 0 */
0065     size_t delta_size = sizeof(gembird_jpd_fixed_rdesc) -
0066                 sizeof(gembird_jpd_faulty_rdesc);
0067     size_t new_size = *rsize + delta_size;
0068 
0069     if (*rsize >= 31 && !memcmp(&rdesc[GEMBIRD_START_FAULTY_RDESC],
0070                     gembird_jpd_faulty_rdesc,
0071                     sizeof(gembird_jpd_faulty_rdesc))) {
0072         new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL);
0073         if (new_rdesc == NULL)
0074             return rdesc;
0075 
0076         dev_info(&hdev->dev,
0077              "fixing Gembird JPD-DualForce 2 report descriptor.\n");
0078 
0079         /* start by copying the end of the rdesc */
0080         memcpy(new_rdesc + delta_size, rdesc, *rsize);
0081 
0082         /* add the correct beginning */
0083         memcpy(new_rdesc, rdesc, GEMBIRD_START_FAULTY_RDESC);
0084 
0085         /* replace the faulty part with the fixed one */
0086         memcpy(new_rdesc + GEMBIRD_START_FAULTY_RDESC,
0087                gembird_jpd_fixed_rdesc,
0088                sizeof(gembird_jpd_fixed_rdesc));
0089 
0090         *rsize = new_size;
0091         rdesc = new_rdesc;
0092     }
0093 
0094     return rdesc;
0095 }
0096 
0097 static const struct hid_device_id gembird_devices[] = {
0098     { HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD,
0099              USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) },
0100     { }
0101 };
0102 MODULE_DEVICE_TABLE(hid, gembird_devices);
0103 
0104 static struct hid_driver gembird_driver = {
0105     .name = "gembird",
0106     .id_table = gembird_devices,
0107     .report_fixup = gembird_report_fixup,
0108 };
0109 module_hid_driver(gembird_driver);
0110 
0111 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
0112 MODULE_DESCRIPTION("HID Gembird joypad driver");
0113 MODULE_LICENSE("GPL");