Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *  HID driver for Cougar 500k Gaming Keyboard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  Copyright (c) 2018 Daniel M. Lambea <dmlambea@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/hid.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/printk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include "hid-ids.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) MODULE_AUTHOR("Daniel M. Lambea <dmlambea@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) MODULE_DESCRIPTION("Cougar 500k Gaming Keyboard");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) MODULE_INFO(key_mappings, "G1-G6 are mapped to F13-F18");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) static bool g6_is_space = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) MODULE_PARM_DESC(g6_is_space,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	"If true, G6 programmable key sends SPACE instead of F18 (default=true)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #define COUGAR_VENDOR_USAGE	0xff00ff00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #define COUGAR_FIELD_CODE	1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #define COUGAR_FIELD_ACTION	2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #define COUGAR_KEY_G1		0x83
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #define COUGAR_KEY_G2		0x84
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define COUGAR_KEY_G3		0x85
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define COUGAR_KEY_G4		0x86
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #define COUGAR_KEY_G5		0x87
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #define COUGAR_KEY_G6		0x78
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define COUGAR_KEY_FN		0x0d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #define COUGAR_KEY_MR		0x6f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #define COUGAR_KEY_M1		0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #define COUGAR_KEY_M2		0x81
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #define COUGAR_KEY_M3		0x82
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) #define COUGAR_KEY_LEDS		0x67
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #define COUGAR_KEY_LOCK		0x6e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) /* Default key mappings. The special key COUGAR_KEY_G6 is defined first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  * because it is more frequent to use the spacebar rather than any other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  * special keys. Depending on the value of the parameter 'g6_is_space',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  * the mapping will be updated in the probe function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) static unsigned char cougar_mapping[][2] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	{ COUGAR_KEY_G6,   KEY_SPACE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	{ COUGAR_KEY_G1,   KEY_F13 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	{ COUGAR_KEY_G2,   KEY_F14 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	{ COUGAR_KEY_G3,   KEY_F15 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	{ COUGAR_KEY_G4,   KEY_F16 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	{ COUGAR_KEY_G5,   KEY_F17 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	{ COUGAR_KEY_LOCK, KEY_SCREENLOCK },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) /* The following keys are handled by the hardware itself, so no special
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)  * treatment is required:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	{ COUGAR_KEY_FN, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	{ COUGAR_KEY_MR, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	{ COUGAR_KEY_M1, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	{ COUGAR_KEY_M2, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	{ COUGAR_KEY_M3, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	{ COUGAR_KEY_LEDS, KEY_RESERVED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	{ 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) struct cougar_shared {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	struct kref kref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	bool enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	struct hid_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) struct cougar {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	bool special_intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	struct cougar_shared *shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) static LIST_HEAD(cougar_udev_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) static DEFINE_MUTEX(cougar_udev_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)  * cougar_fix_g6_mapping - configure the mapping for key G6/Spacebar
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) static void cougar_fix_g6_mapping(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	for (i = 0; cougar_mapping[i][0]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		if (cougar_mapping[i][0] == COUGAR_KEY_G6) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 			cougar_mapping[i][1] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 				g6_is_space ? KEY_SPACE : KEY_F18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 			pr_info("cougar: G6 mapped to %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 				g6_is_space ? "space" : "F18");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	pr_warn("cougar: no mappings defined for G6/spacebar");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)  * Constant-friendly rdesc fixup for mouse interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static __u8 *cougar_report_fixup(struct hid_device *hdev, __u8 *rdesc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 				 unsigned int *rsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	if (rdesc[2] == 0x09 && rdesc[3] == 0x02 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	    (rdesc[115] | rdesc[116] << 8) >= HID_MAX_USAGES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		hid_info(hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 			"usage count exceeds max: fixing up report descriptor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		rdesc[115] = ((HID_MAX_USAGES-1) & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		rdesc[116] = ((HID_MAX_USAGES-1) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	return rdesc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static struct cougar_shared *cougar_get_shared_data(struct hid_device *hdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	struct cougar_shared *shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	/* Try to find an already-probed interface from the same device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	list_for_each_entry(shared, &cougar_udev_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		if (hid_compare_device_paths(hdev, shared->dev, '/')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 			kref_get(&shared->kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 			return shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static void cougar_release_shared_data(struct kref *kref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	struct cougar_shared *shared = container_of(kref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 						    struct cougar_shared, kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	mutex_lock(&cougar_udev_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	list_del(&shared->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	mutex_unlock(&cougar_udev_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	kfree(shared);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static void cougar_remove_shared_data(void *resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	struct cougar *cougar = resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	if (cougar->shared) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 		kref_put(&cougar->shared->kref, cougar_release_shared_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 		cougar->shared = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)  * Bind the device group's shared data to this cougar struct.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)  * If no shared data exists for this group, create and initialize it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int cougar_bind_shared_data(struct hid_device *hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 				   struct cougar *cougar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	struct cougar_shared *shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	mutex_lock(&cougar_udev_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	shared = cougar_get_shared_data(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	if (!shared) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		shared = kzalloc(sizeof(*shared), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		if (!shared) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 			error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		kref_init(&shared->kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		shared->dev = hdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		list_add_tail(&shared->list, &cougar_udev_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	cougar->shared = shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	error = devm_add_action(&hdev->dev, cougar_remove_shared_data, cougar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		mutex_unlock(&cougar_udev_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		cougar_remove_shared_data(cougar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	mutex_unlock(&cougar_udev_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) static int cougar_probe(struct hid_device *hdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 			const struct hid_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	struct cougar *cougar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	struct hid_input *next, *hidinput = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	unsigned int connect_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	cougar = devm_kzalloc(&hdev->dev, sizeof(*cougar), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	if (!cougar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	hid_set_drvdata(hdev, cougar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	error = hid_parse(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		hid_err(hdev, "parse failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		cougar->special_intf = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		connect_mask = HID_CONNECT_HIDRAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		connect_mask = HID_CONNECT_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	error = hid_hw_start(hdev, connect_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		hid_err(hdev, "hw start failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	error = cougar_bind_shared_data(hdev, cougar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 		goto fail_stop_and_cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	/* The custom vendor interface will use the hid_input registered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	 * for the keyboard interface, in order to send translated key codes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	 * to it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	if (hdev->collection->usage == HID_GD_KEYBOARD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		list_for_each_entry_safe(hidinput, next, &hdev->inputs, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 			if (hidinput->registered && hidinput->input != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 				cougar->shared->input = hidinput->input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 				cougar->shared->enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	} else if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 		/* Preinit the mapping table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		cougar_fix_g6_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 		error = hid_hw_open(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 			goto fail_stop_and_cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) fail_stop_and_cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	hid_hw_stop(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)  * Convert events from vendor intf to input key events
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) static int cougar_raw_event(struct hid_device *hdev, struct hid_report *report,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 			    u8 *data, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	struct cougar *cougar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	struct cougar_shared *shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	unsigned char code, action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	cougar = hid_get_drvdata(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	shared = cougar->shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	if (!cougar->special_intf || !shared)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	if (!shared->enabled || !shared->input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 		return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	code = data[COUGAR_FIELD_CODE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	action = data[COUGAR_FIELD_ACTION];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	for (i = 0; cougar_mapping[i][0]; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 		if (code == cougar_mapping[i][0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 			input_event(shared->input, EV_KEY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 				    cougar_mapping[i][1], action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 			input_sync(shared->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 			return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	/* Avoid warnings on the same unmapped key twice */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	if (action != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		hid_warn(hdev, "unmapped special key code %0x: ignoring\n", code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static void cougar_remove(struct hid_device *hdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	struct cougar *cougar = hid_get_drvdata(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	if (cougar) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		/* Stop the vendor intf to process more events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 		if (cougar->shared)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 			cougar->shared->enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		if (cougar->special_intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 			hid_hw_close(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	hid_hw_stop(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static int cougar_param_set_g6_is_space(const char *val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 					const struct kernel_param *kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	ret = param_set_bool(val, kp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	cougar_fix_g6_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static const struct kernel_param_ops cougar_g6_is_space_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	.set	= cougar_param_set_g6_is_space,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	.get	= param_get_bool,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) static const struct hid_device_id cougar_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 			 USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 			 USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	{}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) MODULE_DEVICE_TABLE(hid, cougar_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static struct hid_driver cougar_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	.name			= "cougar",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	.id_table		= cougar_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	.report_fixup		= cougar_report_fixup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	.probe			= cougar_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	.remove			= cougar_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	.raw_event		= cougar_raw_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) module_hid_driver(cougar_driver);