Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  HID driver for gaming keys on Razer Blackwidow gaming keyboards
0004  *  Macro Key Keycodes: M1 = 191, M2 = 192, M3 = 193, M4 = 194, M5 = 195
0005  *
0006  *  Copyright (c) 2021 Jelle van der Waa <jvanderwaa@redhat.com>
0007  */
0008 
0009 #include <linux/device.h>
0010 #include <linux/hid.h>
0011 #include <linux/module.h>
0012 #include <linux/random.h>
0013 #include <linux/sched.h>
0014 #include <linux/usb.h>
0015 #include <linux/wait.h>
0016 
0017 #include "hid-ids.h"
0018 
0019 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
0020 
0021 #define RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE  91
0022 
0023 static bool macro_key_remapping = 1;
0024 module_param(macro_key_remapping, bool, 0644);
0025 MODULE_PARM_DESC(macro_key_remapping, " on (Y) off (N)");
0026 
0027 
0028 static unsigned char blackwidow_init[RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE] = {
0029     0x00,
0030     0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04,
0031     0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0032     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0033     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0034     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0035     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0036     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0037     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0038     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0039     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0040     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0041     0x04, 0x00
0042 };
0043 
0044 static int razer_input_mapping(struct hid_device *hdev,
0045         struct hid_input *hi, struct hid_field *field,
0046         struct hid_usage *usage, unsigned long **bit, int *max)
0047 {
0048 
0049     if (!macro_key_remapping)
0050         return 0;
0051 
0052     if ((usage->hid & HID_UP_KEYBOARD) != HID_UP_KEYBOARD)
0053         return 0;
0054 
0055     switch (usage->hid & ~HID_UP_KEYBOARD) {
0056     case 0x68:
0057         map_key_clear(KEY_MACRO1);
0058         return 1;
0059     case 0x69:
0060         map_key_clear(KEY_MACRO2);
0061         return 1;
0062     case 0x6a:
0063         map_key_clear(KEY_MACRO3);
0064         return 1;
0065     case 0x6b:
0066         map_key_clear(KEY_MACRO4);
0067         return 1;
0068     case 0x6c:
0069         map_key_clear(KEY_MACRO5);
0070         return 1;
0071     }
0072 
0073     return 0;
0074 }
0075 
0076 static int razer_probe(struct hid_device *hdev, const struct hid_device_id *id)
0077 {
0078     char *buf;
0079     int ret = 0;
0080 
0081     ret = hid_parse(hdev);
0082     if (ret)
0083         return ret;
0084 
0085     /*
0086      * Only send the enable macro keys command for the third device
0087      * identified as mouse input.
0088      */
0089     if (hdev->type == HID_TYPE_USBMOUSE) {
0090         buf = kmemdup(blackwidow_init, RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE, GFP_KERNEL);
0091         if (buf == NULL)
0092             return -ENOMEM;
0093 
0094         ret = hid_hw_raw_request(hdev, 0, buf, RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE,
0095                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
0096         if (ret != RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE)
0097             hid_err(hdev, "failed to enable macro keys: %d\n", ret);
0098 
0099         kfree(buf);
0100     }
0101 
0102     return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
0103 }
0104 
0105 static const struct hid_device_id razer_devices[] = {
0106     { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
0107         USB_DEVICE_ID_RAZER_BLACKWIDOW) },
0108     { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
0109         USB_DEVICE_ID_RAZER_BLACKWIDOW_CLASSIC) },
0110     { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
0111         USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE) },
0112     { }
0113 };
0114 MODULE_DEVICE_TABLE(hid, razer_devices);
0115 
0116 static struct hid_driver razer_driver = {
0117     .name = "razer",
0118     .id_table = razer_devices,
0119     .input_mapping = razer_input_mapping,
0120     .probe = razer_probe,
0121 };
0122 module_hid_driver(razer_driver);
0123 
0124 MODULE_AUTHOR("Jelle van der Waa <jvanderwaa@redhat.com>");
0125 MODULE_LICENSE("GPL");