Linux Audio

Check our new training course

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