diff --git a/README.md b/README.md index 6147ee362157f0f94be6c2dc0c5e3eb3624e76cf..57ca21d2b64a4eb30275719d02a929d2d7d69247 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ The devices below are fully feature supported by OpenRazer, which means all avai | Razer DeathAdder V2 Pro (Wireless) | 1532:007D | | Razer Basilisk X HyperSpeed | 1532:0083 | | Razer DeathAdder V2 | 1532:0084 | +| Razer Basilisk V2 | 1532:0085 | | Razer Viper Mini | 1532:008A | | Razer DeathAdder V2 Mini | 1532:008C | | Razer Naga Left-Handed Edition | 1532:008D | diff --git a/daemon/openrazer_daemon/hardware/mouse.py b/daemon/openrazer_daemon/hardware/mouse.py index 1d44be233fdfd364145c8485a0e2d2560e7b88fd..52721ef0883a3c6a4883032ec3e5e09e449dcca2 100644 --- a/daemon/openrazer_daemon/hardware/mouse.py +++ b/daemon/openrazer_daemon/hardware/mouse.py @@ -2071,6 +2071,59 @@ class RazerBasilisk(__RazerDeviceSpecialBrightnessSuspend): self.disable_notify = False +class RazerBasiliskV2(__RazerDeviceSpecialBrightnessSuspend): + """ + Class for the Razer Basilisk V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_V2-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0085 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'get_logo_brightness', 'set_logo_brightness', 'get_scroll_brightness', 'set_scroll_brightness', + # Logo + 'set_logo_static_naga_hex_v2', 'set_logo_spectrum_naga_hex_v2', 'set_logo_none_naga_hex_v2', 'set_logo_reactive_naga_hex_v2', 'set_logo_breath_random_naga_hex_v2', 'set_logo_breath_single_naga_hex_v2', 'set_logo_breath_dual_naga_hex_v2', + # Scroll wheel + 'set_scroll_static_naga_hex_v2', 'set_scroll_spectrum_naga_hex_v2', 'set_scroll_none_naga_hex_v2', 'set_scroll_reactive_naga_hex_v2', 'set_scroll_breath_random_naga_hex_v2', 'set_scroll_breath_single_naga_hex_v2', 'set_scroll_breath_dual_naga_hex_v2', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1617/1617_basilisk-v2.png" + + DPI_MAX = 20000 + + def _suspend_device(self): + """ + Suspend the device + + Get the current brightness level, store it for later and then set the brightness to 0 + """ + self.suspend_args.clear() + self.suspend_args['brightness'] = (_da_get_logo_brightness(self), _da_get_scroll_brightness(self)) + + # Todo make it context? + self.disable_notify = True + _da_set_logo_brightness(self, 0) + _da_set_scroll_brightness(self, 0) + self.disable_notify = False + + def _resume_device(self): + """ + Resume the device + + Get the last known brightness and then set the brightness + """ + logo_brightness = self.suspend_args.get('brightness', (100, 100))[0] + scroll_brightness = self.suspend_args.get('brightness', (100, 100))[1] + + self.disable_notify = True + _da_set_logo_brightness(self, logo_brightness) + _da_set_scroll_brightness(self, scroll_brightness) + self.disable_notify = False + + class RazerDeathAdderV2(__RazerDeviceSpecialBrightnessSuspend): """ Class for the Razer DeathAdder V2 diff --git a/driver/razermouse_driver.c b/driver/razermouse_driver.c index 0a7a16974f250ac1c8ff5b6d97a42dbfdab569d0..2dab2f45b18f7897c1c7f67f3bd0cb87163986da 100644 --- a/driver/razermouse_driver.c +++ b/driver/razermouse_driver.c @@ -24,6 +24,7 @@ #include <linux/init.h> #include <linux/usb/input.h> #include <linux/hid.h> +#include <linux/hrtimer.h> #include <linux/random.h> #include "razermouse_driver.h" @@ -394,6 +395,10 @@ static ssize_t razer_attr_read_device_type(struct device *dev, struct device_att device_type = "Razer Basilisk\n"; break; + case USB_DEVICE_ID_RAZER_BASILISK_V2: + device_type = "Razer Basilisk V2\n"; + break; + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: device_type = "Razer DeathAdder V2\n"; break; @@ -456,6 +461,7 @@ static ssize_t razer_attr_read_get_firmware_version(struct device *dev, struct d case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; @@ -567,6 +573,7 @@ static ssize_t razer_attr_write_mode_custom(struct device *dev, struct device_at case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_custom_frame(); report.transaction_id.id = 0x1f; break; @@ -801,6 +808,7 @@ static ssize_t razer_attr_read_get_serial(struct device *dev, struct device_attr case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; } @@ -978,6 +986,7 @@ static ssize_t razer_attr_read_poll_rate(struct device *dev, struct device_attri case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; } @@ -1047,6 +1056,7 @@ static ssize_t razer_attr_write_poll_rate(struct device *dev, struct device_attr case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; } @@ -1279,6 +1289,7 @@ static ssize_t razer_attr_write_mouse_dpi(struct device *dev, struct device_attr case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; } @@ -1339,6 +1350,7 @@ static ssize_t razer_attr_read_mouse_dpi(struct device *dev, struct device_attri case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_misc_get_dpi_xy(NOSTORE); report.transaction_id.id = 0x1f; break; @@ -1389,6 +1401,54 @@ static ssize_t razer_attr_read_mouse_dpi(struct device *dev, struct device_attri return sprintf(buf, "%u:%u\n", dpi_x, dpi_y); } +static ssize_t razer_attr_write_tilt_hwheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned int tilt_hwheel; + if (kstrtouint(buf, 0, &tilt_hwheel) < 0) + return -EINVAL; + device->tilt_hwheel = !!tilt_hwheel; + return count; +} + +static ssize_t razer_attr_read_tilt_hwheel(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + return sprintf(buf, "%u\n", device->tilt_hwheel); +} + +static ssize_t razer_attr_write_tilt_repeat(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned int tilt_repeat; + if (kstrtouint(buf, 0, &tilt_repeat) < 0) + return -EINVAL; + device->tilt_repeat = tilt_repeat; + return count; +} + +static ssize_t razer_attr_read_tilt_repeat(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + return sprintf(buf, "%u\n", device->tilt_repeat); +} + +static ssize_t razer_attr_write_tilt_repeat_delay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned int tilt_repeat_delay; + if (kstrtouint(buf, 0, &tilt_repeat_delay) < 0) + return -EINVAL; + device->tilt_repeat_delay = tilt_repeat_delay; + return count; +} + +static ssize_t razer_attr_read_tilt_repeat_delay(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + return sprintf(buf, "%u\n", device->tilt_repeat_delay); +} + /** * Write device file "dpi_stages" * @@ -1673,6 +1733,11 @@ static ssize_t razer_attr_write_set_key_row(struct device *dev, struct device_at report = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); break; + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + report.transaction_id.id = 0x1f; + break; + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: report = razer_chroma_misc_one_row_set_custom_frame(start_col, stop_col, (unsigned char*)&buf[offset]); @@ -1720,6 +1785,7 @@ static ssize_t razer_attr_write_device_mode(struct device *dev, struct device_at case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; @@ -1788,6 +1854,7 @@ static ssize_t razer_attr_read_device_mode(struct device *dev, struct device_att case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; } @@ -1817,6 +1884,7 @@ static ssize_t razer_attr_read_scroll_led_brightness(struct device *dev, struct case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_get_brightness(VARSTORE, SCROLL_WHEEL_LED); report.transaction_id.id = 0x1f; break; @@ -1864,6 +1932,7 @@ static ssize_t razer_attr_write_scroll_led_brightness(struct device *dev, struct case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_brightness(VARSTORE, SCROLL_WHEEL_LED, brightness); report.transaction_id.id = 0x1f; break; @@ -1911,6 +1980,7 @@ static ssize_t razer_attr_read_logo_led_brightness(struct device *dev, struct de case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_get_brightness(VARSTORE, LOGO_LED); report.transaction_id.id = 0x1f; break; @@ -1967,6 +2037,7 @@ static ssize_t razer_attr_write_logo_led_brightness(struct device *dev, struct d case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_brightness(VARSTORE, LOGO_LED, brightness); report.transaction_id.id = 0x1f; break; @@ -2436,6 +2507,7 @@ static ssize_t razer_attr_write_scroll_mode_spectrum(struct device *dev, struct case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, SCROLL_WHEEL_LED); report.transaction_id.id = 0x1f; break; @@ -2485,6 +2557,7 @@ static ssize_t razer_attr_write_scroll_mode_reactive(struct device *dev, struct case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, SCROLL_WHEEL_LED, speed, (struct razer_rgb*)&buf[1]); report.transaction_id.id = 0x1f; break; @@ -2545,6 +2618,7 @@ static ssize_t razer_attr_write_scroll_mode_breath(struct device *dev, struct de case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_V2: case USB_DEVICE_ID_RAZER_DEATHADDER_V2: switch(count) { case 3: // Single colour mode @@ -2565,6 +2639,7 @@ static ssize_t razer_attr_write_scroll_mode_breath(struct device *dev, struct de switch(usb_dev->descriptor.idProduct) { case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; @@ -2613,6 +2688,7 @@ static ssize_t razer_attr_write_scroll_mode_static(struct device *dev, struct de case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_static(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); report.transaction_id.id = 0x1f; break; @@ -2666,6 +2742,7 @@ static ssize_t razer_attr_write_scroll_mode_none(struct device *dev, struct devi case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_none(VARSTORE, SCROLL_WHEEL_LED); report.transaction_id.id = 0x1f; break; @@ -2756,6 +2833,7 @@ static ssize_t razer_attr_write_logo_mode_spectrum(struct device *dev, struct de case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, LOGO_LED); report.transaction_id.id = 0x1f; break; @@ -2813,6 +2891,7 @@ static ssize_t razer_attr_write_logo_mode_reactive(struct device *dev, struct de case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, LOGO_LED, speed, (struct razer_rgb*)&buf[1]); report.transaction_id.id = 0x1f; break; @@ -2879,6 +2958,7 @@ static ssize_t razer_attr_write_logo_mode_breath(struct device *dev, struct devi case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_V2: case USB_DEVICE_ID_RAZER_DEATHADDER_V2: case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: @@ -2902,6 +2982,7 @@ static ssize_t razer_attr_write_logo_mode_breath(struct device *dev, struct devi switch(usb_dev->descriptor.idProduct) { case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report.transaction_id.id = 0x1f; break; @@ -2958,6 +3039,7 @@ static ssize_t razer_attr_write_logo_mode_static(struct device *dev, struct devi case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_static(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); report.transaction_id.id = 0x1f; break; @@ -3018,6 +3100,7 @@ static ssize_t razer_attr_write_logo_mode_none(struct device *dev, struct device case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: report = razer_chroma_extended_matrix_effect_none(VARSTORE, LOGO_LED); report.transaction_id.id = 0x1f; break; @@ -3411,6 +3494,10 @@ static DEVICE_ATTR(device_mode, 0660, razer_attr_read_device_mode, static DEVICE_ATTR(device_serial, 0440, razer_attr_read_get_serial, NULL); static DEVICE_ATTR(device_idle_time, 0660, razer_attr_read_get_idle_time, razer_attr_write_set_idle_time); +static DEVICE_ATTR(tilt_hwheel, 0660, razer_attr_read_tilt_hwheel, razer_attr_write_tilt_hwheel); +static DEVICE_ATTR(tilt_repeat, 0660, razer_attr_read_tilt_repeat, razer_attr_write_tilt_repeat); +static DEVICE_ATTR(tilt_repeat_delay, 0660, razer_attr_read_tilt_repeat_delay, razer_attr_write_tilt_repeat_delay); + static DEVICE_ATTR(charge_level, 0440, razer_attr_read_get_battery, NULL); static DEVICE_ATTR(charge_status, 0440, razer_attr_read_is_charging, NULL); static DEVICE_ATTR(charge_effect, 0220, NULL, razer_attr_write_set_charging_effect); @@ -3476,6 +3563,200 @@ static DEVICE_ATTR(right_matrix_effect_none, 0220, NULL, static DEVICE_ATTR(backlight_led_state, 0660, razer_attr_read_backlight_led_state, razer_attr_write_backlight_led_state); +#define REP4_DPI_UP 0x20 +#define REP4_DPI_DN 0x21 +#define REP4_TILT_L 0x22 +#define REP4_TILT_R 0x23 +#define REP4_PROFILE 0x50 +#define REP4_SNIPER 0x51 + +#define BIT_TILT_L 5 +#define BIT_TILT_R 6 + +/** + * Map "Report 4" codes to evdev key codes + */ +static const __u16 rep4_key_codes[] = { + [REP4_TILT_L] = BTN_BACK, /* BTN_MOUSE + 6 */ + [REP4_TILT_R] = BTN_FORWARD, /* BTN_MOUSE + 5 */ + [REP4_SNIPER] = BTN_TASK, /* BTN_MOUSE + 7 */ + [REP4_DPI_UP] = BTN_MOUSE + 8, + [REP4_DPI_DN] = BTN_MOUSE + 9, + [REP4_PROFILE] = BTN_MOUSE + 10, + /* NOTE: Highest legal mouse button is BTN_MOUSE + 15 */ +}; + +struct button_mapping { + u8 bit; + __u16 code; /* when tilt_hwheel == 0 */ + __s32 hwheel_value; /* when tilt_hwheel == 1 */ +}; + +/** + * Map bits in the first byte of the mouse report to evdev keycodes + * and REL_HWHEEL values + */ +static const struct button_mapping button_mappings[] = { + {BIT_TILT_L, BTN_BACK, -1}, + {BIT_TILT_R, BTN_FORWARD, 1}, +}; + +/** + * Convert an evdev mouse button code to the corresponding HID usage + */ +u32 mouse_button_to_usage(__u16 code) +{ + return HID_UP_BUTTON + (code - BTN_MOUSE) + 1; +} + +/** + * Send the MSC_SCAN event for the usage code associated with an evdev + * mouse button code + */ +void input_button_msc_scan(struct input_dev *input, __u16 button) +{ + input_event(input, EV_MSC, MSC_SCAN, mouse_button_to_usage(button)); +} + +/** + * Look up and send the evdev key associated with the Razer "report 4" + * code + */ +void input_rep4_code(struct input_dev *input, u8 code, __s32 value) +{ + if (code < ARRAY_SIZE(rep4_key_codes) && rep4_key_codes[code]) { + unsigned int button = rep4_key_codes[code]; + input_button_msc_scan(input, button); + input_report_key(input, button, value); + input_sync(input); + } +} + +/** + * Timer callback for wheel tilt repeating + */ +static enum hrtimer_restart wheel_tilt_repeat(struct hrtimer *timer) +{ + struct razer_mouse_device *dev = + container_of(timer, struct razer_mouse_device, repeat_timer); + input_report_rel(dev->input, REL_HWHEEL, dev->hwheel_value); + input_sync(dev->input); + if (dev->tilt_repeat) + hrtimer_forward_now(timer, ms_to_ktime(dev->tilt_repeat)); + return HRTIMER_RESTART; +} + +/** + * Send a tilt-wheel event and, if configured, start the key-repeat timer + */ +static void tilt_hwheel_start(struct razer_mouse_device *rdev, + __s32 rel_value) +{ + input_report_rel(rdev->input, REL_HWHEEL, rel_value); + input_sync(rdev->input); + + if (rdev->tilt_repeat && rdev->tilt_repeat_delay) { + rdev->hwheel_value = rel_value; + hrtimer_start_range_ns( + &rdev->repeat_timer, ms_to_ktime(rdev->tilt_repeat_delay), + 1000, HRTIMER_MODE_REL); + } +} + +/** + * Stop the tilt wheel key-repeat timer + */ +static void tilt_hwheel_stop(struct razer_mouse_device *rdev) +{ + hrtimer_cancel(&rdev->repeat_timer); +} + +/** + * Test if a device is a HID device + */ +static int dev_is_on_bus(struct device *dev, void *data) +{ + return (dev->bus == data); +} + +/** + * Find an interface on a usb_device with the specified protocol + */ +struct usb_interface *find_intf_with_proto(struct usb_device *usbdev, u8 proto) +{ + struct usb_interface *intf; + int i; + + for (i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++) { + intf = usb_ifnum_to_if(usbdev, i); + if (intf && intf->cur_altsetting->desc.bInterfaceProtocol == proto) + return intf; + } + + return NULL; +} + +/** + * Walk up the device tree from an interface to the device it is a + * part of, then back down through the interface with protocol == MOUSE + * to the razer_mouse_device associated with it + */ +static struct razer_mouse_device *find_mouse(struct hid_device *hdev) +{ + struct bus_type *hid_bus_type = hdev->dev.bus; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usbdev = interface_to_usbdev(intf); + struct usb_interface *m_intf = find_intf_with_proto(usbdev, USB_INTERFACE_PROTOCOL_MOUSE); + struct device *dev; + struct razer_mouse_device *rdev; + + if (!m_intf) + return NULL; + + dev = device_find_child(&m_intf->dev, hid_bus_type, dev_is_on_bus); + if (!dev) + return NULL; + + rdev = dev_get_drvdata(dev); + put_device(dev); + return rdev; +} + +/** + * Test if a bit is cleared in 'prev' and set in 'cur' + */ +static int rising_bit(u8 prev, u8 cur, u8 mask) +{ + return !(prev & mask) && cur & mask; +} + +/** + * Test if a bit is set in 'prev' and cleared in 'cur' + */ +static int falling_bit(u8 prev, u8 cur, u8 mask) +{ + return prev & mask && !(cur & mask); +} + +/** + * Test if a bit is different between 'prev' and 'cur' + */ +static int edge_bit(u8 prev, u8 cur, u8 mask) +{ + return (prev & mask) != (cur & mask); +} + +/** + * Search a byte array for a value + */ +static int search(u8 *array, u8 value, unsigned n) +{ + while (n--) { + if (*array++ == value) + return 1; + } + return 0; +} /** * Raw event function @@ -3483,41 +3764,138 @@ static DEVICE_ATTR(backlight_led_state, 0660, razer_attr_read_backlig static int razer_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct razer_mouse_device *rdev = hid_get_drvdata(hdev); + + switch (hdev->product) { + case USB_DEVICE_ID_RAZER_BASILISK_V2: + /* Detect wheel tilt edges */ + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { + int i; + for (i = 0; i < ARRAY_SIZE(button_mappings); i++) { + const struct button_mapping *mapping = &button_mappings[i]; + u8 mask = 1 << mapping->bit; + if (mapping->hwheel_value && rdev->tilt_hwheel) { + __s32 rel_value = mapping->hwheel_value; + if (rising_bit(rdev->button_byte, data[0], mask)) + tilt_hwheel_start(rdev, rel_value); + if (falling_bit(rdev->button_byte, data[0], mask)) + tilt_hwheel_stop(rdev); + } else if (edge_bit(rdev->button_byte, data[0], mask)) { + unsigned int code = mapping->code; + input_button_msc_scan(rdev->input, code); + input_report_key(rdev->input, code, !!(data[0] & mask)); + input_sync(rdev->input); + } + } + rdev->button_byte = data[0]; + } - // The event were looking for is 16 bytes long and starts with 0x04 - if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD && size == 16 && data[0] == 0x04) { - // Convert 04... to 0100... - int index = size-1; // This way we start at 2nd last value, does subtract 1 from the 15key rollover though (not an issue cmon) - u8 cur_value = 0x00; + /* Detect buttons reported on the keyboard interface */ + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD && size == 16 && data[0] == 0x04) { + struct razer_mouse_device *m_rdev = find_mouse(hdev); + int i; - while(--index > 0) { - cur_value = data[index]; - if(cur_value == 0x00) { // Skip 0x00 - continue; + if (!m_rdev) { + printk(KERN_WARNING "razermouse: Couldn't find mouse intf from kbd intf"); + return 1; } - switch(cur_value) { - case 0x20: // DPI Up - cur_value = 0x68; // F13 - break; - case 0x21: // DPI Down - cur_value = 0x69; // F14 - break; - case 0x22: // Wheel Left - cur_value = 0x6A; // F15 - break; - case 0x23: // Wheel Right - cur_value = 0x6B; // F16 - break; + for (i = 1; i < size; i++) { + if (!search(rdev->rep4 + 1, data[i], size - 1)) + input_rep4_code(m_rdev->input, data[i], 1); + if (!search(data + 1, rdev->rep4[i], size - 1)) + input_rep4_code(m_rdev->input, rdev->rep4[i], 0); + } + memcpy(rdev->rep4, data, 16); + return 1; + } + break; + default: + // The event were looking for is 16 bytes long and starts with 0x04 + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD && size == 16 && data[0] == 0x04) { + // Convert 04... to 0100... + int index = size-1; // This way we start at 2nd last value, does subtract 1 from the 15key rollover though (not an issue cmon) + u8 cur_value = 0x00; + + while(--index > 0) { + cur_value = data[index]; + if(cur_value == 0x00) { // Skip 0x00 + continue; + } + + switch(cur_value) { + case 0x20: // DPI Up + cur_value = 0x68; // F13 + break; + case 0x21: // DPI Down + cur_value = 0x69; // F14 + break; + case 0x22: // Wheel Left + cur_value = 0x6A; // F15 + break; + case 0x23: // Wheel Right + cur_value = 0x6B; // F16 + break; + } + + data[index+1] = cur_value; } - data[index+1] = cur_value; + + data[0] = 0x01; + data[1] = 0x00; + return 1; } + break; + } + return 0; +} + +/** + * Input mapping function + */ +static int +razer_input_mapping(struct hid_device *hdev, struct hid_input *hidinput, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + /* Some higher nonstandard mouse buttons are reported in + * 15-element arrays on reports 4 and 5 with usage 0x10003. If + * hid-core tries to interpret this misshapen descriptor it will + * botch it and add spurious event codes to input->evkey. */ + if (field->application == HID_UP_GENDESK + && usage->hid == (HID_UP_GENDESK | 0x0003)) { + return -1; + } + return 0; +} - data[0] = 0x01; - data[1] = 0x00; - return 1; +/** + * Input configured function + */ +static int razer_input_configured(struct hid_device *hdev, + struct hid_input *hidinput) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct razer_mouse_device *dev = hid_get_drvdata(hdev); + + dev->input = hidinput->input; + + if (intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { + switch (hdev->product) { + case USB_DEVICE_ID_RAZER_BASILISK_V2: + /* Linux HID doesn't detect the Basilisk V2's tilt wheel + * or buttons beyond the first 5 */ + input_set_capability(hidinput->input, EV_REL, REL_HWHEEL); + input_set_capability(hidinput->input, EV_KEY, BTN_FORWARD); + input_set_capability(hidinput->input, EV_KEY, BTN_BACK); + input_set_capability(hidinput->input, EV_KEY, BTN_TASK); + input_set_capability(hidinput->input, EV_KEY, BTN_MOUSE + 8); + input_set_capability(hidinput->input, EV_KEY, BTN_MOUSE + 9); + input_set_capability(hidinput->input, EV_KEY, BTN_MOUSE + 10); + break; + } } return 0; @@ -3553,6 +3931,13 @@ static void razer_mouse_init(struct razer_mouse_device *dev, struct usb_interfac dev->da3_5g.dpi = 1; // 3500 DPI dev->da3_5g.profile = 1; // Profile 1 dev->da3_5g.poll = 1; // Poll rate 1000 + + // Setup tilt wheel HWHEEL emulation + hrtimer_init(&dev->repeat_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + dev->repeat_timer.function = wheel_tilt_repeat; + dev->tilt_hwheel = 1; + dev->tilt_repeat_delay = 250; + dev->tilt_repeat = 33; } /** @@ -3654,6 +4039,11 @@ static int razer_mouse_probe(struct hid_device *hdev, const struct hid_device_id CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); break; + case USB_DEVICE_ID_RAZER_BASILISK_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_tilt_hwheel); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_tilt_repeat_delay); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_tilt_repeat); + /* Fall through */ case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: case USB_DEVICE_ID_RAZER_BASILISK: case USB_DEVICE_ID_RAZER_DEATHADDER_V2: @@ -4169,6 +4559,11 @@ static void razer_mouse_disconnect(struct hid_device *hdev) device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); break; + case USB_DEVICE_ID_RAZER_BASILISK_V2: + device_remove_file(&hdev->dev, &dev_attr_tilt_hwheel); + device_remove_file(&hdev->dev, &dev_attr_tilt_repeat_delay); + device_remove_file(&hdev->dev, &dev_attr_tilt_repeat); + /* Fall through */ case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: case USB_DEVICE_ID_RAZER_BASILISK: case USB_DEVICE_ID_RAZER_DEATHADDER_V2: @@ -4559,6 +4954,8 @@ static void razer_mouse_disconnect(struct hid_device *hdev) hid_hw_stop(hdev); + hrtimer_cancel(&dev->repeat_timer); + kfree(dev); dev_info(&intf->dev, "Razer Device disconnected\n"); } @@ -4614,6 +5011,7 @@ static const struct hid_device_id razer_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V2) }, { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V2) }, { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS) }, @@ -4638,6 +5036,8 @@ static struct hid_driver razer_mouse_driver = { .remove = razer_mouse_disconnect, .raw_event = razer_raw_event, + .input_mapping = razer_input_mapping, + .input_configured = razer_input_configured, }; module_hid_driver(razer_mouse_driver); diff --git a/driver/razermouse_driver.h b/driver/razermouse_driver.h index aab8656eb75dc9deeecdac2b90165a756cac83ac..adf7a6928958ab3321107628b151f861c88c3d56 100644 --- a/driver/razermouse_driver.h +++ b/driver/razermouse_driver.h @@ -63,6 +63,7 @@ #define USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS 0x007D #define USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED 0x0083 #define USB_DEVICE_ID_RAZER_DEATHADDER_V2 0x0084 +#define USB_DEVICE_ID_RAZER_BASILISK_V2 0x0085 #define USB_DEVICE_ID_RAZER_VIPER_MINI 0x008A #define USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI 0x008C #define USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020 0x008D @@ -91,6 +92,16 @@ struct razer_mouse_device { struct usb_device *usb_dev; struct mutex lock; + + struct input_dev *input; + struct hrtimer repeat_timer; + unsigned int tilt_hwheel; + unsigned int tilt_repeat_delay; + unsigned int tilt_repeat; + __s32 hwheel_value; + u8 button_byte; // Previous value of mouse button byte in HID record + u8 rep4[16]; // Previous value of report 4 on the keyboard intf + unsigned char usb_interface_protocol; unsigned char usb_interface_subclass; diff --git a/install_files/appstream/io.github.openrazer.openrazer.metainfo.xml b/install_files/appstream/io.github.openrazer.openrazer.metainfo.xml index 46af1acb51868f05d627fc697f04f2aa2a277a09..a9b5f585713b8272498138d23b7cda22a5444e25 100644 --- a/install_files/appstream/io.github.openrazer.openrazer.metainfo.xml +++ b/install_files/appstream/io.github.openrazer.openrazer.metainfo.xml @@ -67,6 +67,7 @@ <modalias>usb:v1532p007Dd*</modalias> <modalias>usb:v1532p0083d*</modalias> <modalias>usb:v1532p0084d*</modalias> + <modalias>usb:v1532p0085d*</modalias> <modalias>usb:v1532p008Ad*</modalias> <modalias>usb:v1532p008Cd*</modalias> <modalias>usb:v1532p008Dd*</modalias> diff --git a/install_files/udev/99-razer.rules b/install_files/udev/99-razer.rules index d5b9f646068640fcaa2af1052b47c100c12d972a..4155ce42e2104c4f595b6dfb9e987870b398aa06 100644 --- a/install_files/udev/99-razer.rules +++ b/install_files/udev/99-razer.rules @@ -5,7 +5,7 @@ GOTO="razer_end" LABEL="razer_vendor" # Mice -ATTRS{idProduct}=="0013|0016|0020|0024|0025|002e|002f|0032|0034|0036|0037|0038|0039|0040|0041|0042|0043|0044|0045|0046|0048|004c|004f|0050|0053|0054|0059|005a|005b|005c|005e|0060|0062|0064|0067|006a|006b|006c|006e|006f|0070|0071|0072|0073|0078|007a|007b|007c|007d|0083|0084|008a|008c|008d", \ +ATTRS{idProduct}=="0013|0016|0020|0024|0025|002e|002f|0032|0034|0036|0037|0038|0039|0040|0041|0042|0043|0044|0045|0046|0048|004c|004f|0050|0053|0054|0059|005a|005b|005c|005e|0060|0062|0064|0067|006a|006b|006c|006e|006f|0070|0071|0072|0073|0078|007a|007b|007c|007d|0083|0084|0085|008a|008c|008d", \ ATTRS{idVendor}=="1532", \ ENV{ID_RAZER_CHROMA}="1", ENV{RAZER_DRIVER}="razermouse" diff --git a/pylib/openrazer/_fake_driver/razerbasiliskv2.cfg b/pylib/openrazer/_fake_driver/razerbasiliskv2.cfg new file mode 100644 index 0000000000000000000000000000000000000000..925f02243722d81815cf290cc7a42cdaf077e5e2 --- /dev/null +++ b/pylib/openrazer/_fake_driver/razerbasiliskv2.cfg @@ -0,0 +1,26 @@ +[device] +dir_name = 0003:1532:0085.0001 +name = Razer Basilisk V2 +files = r,device_serial,XX0000000085 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_breath + w,logo_matrix_effect_none + w,logo_matrix_effect_reactive + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_reactive + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/scripts/generate_fake_driver.sh b/scripts/generate_fake_driver.sh index dd5e8b313e40c8d1a652a6bd9e14dd031eb1587b..e50a5417f464af207de30d414168cc86c111ec7e 100755 --- a/scripts/generate_fake_driver.sh +++ b/scripts/generate_fake_driver.sh @@ -71,6 +71,9 @@ declare -A files_metadata=( ["scroll_matrix_effect_spectrum"]="w;" ["scroll_matrix_effect_static"]="w;" ["scroll_matrix_effect_wave"]="w;" + ["tilt_hwheel"]="rw;0" + ["tilt_repeat"]="rw;0" + ["tilt_repeat_delay"]="rw;0" ["version"]="r;1.0.0" )