^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);