diff --git a/README.md b/README.md index 4607d27c..76e53402 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ Mice: - Razer Basilisk Ultimate - Razer Basilisk V2 - Razer Basilisk V3 +- Razer Basilisk V3 X HyperSpeed - Razer DeathAdder 3 5G - Razer DeathAdder 1800 - Razer DeathAdder 2013 (under older mouse effects) @@ -274,3 +275,7 @@ Builds on work done by these amazing projects: - [openrazer](https://github.com/openrazer/openrazer) - [osx-razer-blade](https://github.com/kprinssu/osx-razer-blade) - [osx-razer-led](https://github.com/dylanparker/osx-razer-led) +## New Device Support +- ✨ Added support for **Razer Basilisk V3 X HyperSpeed** +- Full RGB lighting control and wireless connectivity support +- Compatible with all standard mouse effects (static, breathing, spectrum cycling, etc.) \ No newline at end of file diff --git a/librazermacos b/librazermacos index 325c96a6..ae471899 160000 --- a/librazermacos +++ b/librazermacos @@ -1 +1 @@ -Subproject commit 325c96a62afd87debbaf4f51d8c9f569e45657bb +Subproject commit ae4718997f729bbd8afd17731b9f0172784fe940 diff --git a/openrazer/.builds/alpine.yml b/openrazer/.builds/alpine.yml new file mode 100644 index 00000000..54deb1e8 --- /dev/null +++ b/openrazer/.builds/alpine.yml @@ -0,0 +1,79 @@ +image: alpine/latest +packages: + - astyle + - dbus-x11 + - linux-lts-dev + - py3-autopep8 + - py3-daemonize + - py3-dbus + - py3-gobject3 + - py3-numpy + - py3-pylint + - py3-setproctitle + - py3-setuptools + - py3-udev + - sed +sources: + - https://github.com/openrazer/openrazer +tasks: + - check-formatting: | + cd openrazer + + # Check the formatting of the driver and the python code + # Disable astyle for now: + # https://gitlab.com/saalen/astyle/-/issues/91 + #./scripts/ci/check-astyle-formatting.sh + ./scripts/ci/check-autopep8-formatting.sh + + - check-misc: | + cd openrazer + + # Check with pylint for errors + ./scripts/ci/check-pylint.sh + # Check for auto-generated files + ./scripts/ci/test-auto-generate.sh + # Check for hex casing issues + ./scripts/ci/test-hex-casing.sh + + - compile-driver: | + cd openrazer + + kerneldirs=(/lib/modules/*/build) + kerneldir="${kerneldirs[0]}" + + # Work around the following error by disabling gcc plugins + # cc1: error: incompatible gcc/plugin versions + # cc1: error: failed to initialize plugin ./scripts/gcc-plugins/stackleak_plugin.so + sudo truncate -s 0 "$kerneldir"/scripts/Makefile.gcc-plugins + + # Compile the kernel driver + echo "ccflags-y := -Wall -Werror" >> driver/Makefile + make KERNELDIR="$kerneldir" + + - functional-test-setup: | + # The daemon wants the user to be in the plugdev group + sudo addgroup -S plugdev + sudo addgroup -S $USER plugdev + + - functional-test: | + cd openrazer + + # Clean up background processes on exit + trap "pkill -f openrazer-daemon; + pkill -f create_fake_dev; + pkill -f dbus-daemon" EXIT + + # Launch dbus + eval $(dbus-launch --sh-syntax) + + # Setup the fake driver + ./scripts/ci/setup-fakedriver.sh + + # Launch the daemon + ./scripts/ci/launch-daemon.sh + + # Wait for the daemon to be ready + sleep 5 + + # Run a simple check to see if the daemon is alive + ./scripts/ci/test-daemon.sh diff --git a/openrazer/.builds/ubuntu.yml b/openrazer/.builds/ubuntu.yml new file mode 100644 index 00000000..3b41a46c --- /dev/null +++ b/openrazer/.builds/ubuntu.yml @@ -0,0 +1,13 @@ +image: ubuntu/oldlts +packages: + - linux-headers-generic +sources: + - https://github.com/openrazer/openrazer +tasks: + - compile-driver: | + cd openrazer + + # Compile the kernel driver + echo "ccflags-y := -Wall -Werror" >> driver/Makefile + kerneldir=(/lib/modules/*/build) + make KERNELDIR="${kerneldir[0]}" diff --git a/openrazer/.bumpversion.cfg b/openrazer/.bumpversion.cfg new file mode 100644 index 00000000..006f202d --- /dev/null +++ b/openrazer/.bumpversion.cfg @@ -0,0 +1,17 @@ +[bumpversion] +current_version = 3.10.3 + +[bumpversion:file:pylib/openrazer/client/__init__.py] + +[bumpversion:file:daemon/openrazer_daemon/daemon.py] + +[bumpversion:file:driver/razercommon.h] + +[bumpversion:file:pylib/setup.py] + +[bumpversion:file:daemon/setup.py] + +[bumpversion:file:Makefile] + +[bumpversion:file:install_files/dkms/dkms.conf] + diff --git a/openrazer/.github/FUNDING.yml b/openrazer/.github/FUNDING.yml new file mode 100644 index 00000000..1aee0e17 --- /dev/null +++ b/openrazer/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ["https://www.paypal.me/z3ntu", "https://www.paypal.me/LukeHorwell", "https://www.paypal.me/terrycain1337"] diff --git a/openrazer/.github/ISSUE_TEMPLATE/00-new-device.yml b/openrazer/.github/ISSUE_TEMPLATE/00-new-device.yml new file mode 100644 index 00000000..bb96ed93 --- /dev/null +++ b/openrazer/.github/ISSUE_TEMPLATE/00-new-device.yml @@ -0,0 +1,108 @@ +name: "Support for a new device" +title: "Support for Razer [name]" +description: "Provide details to request support for a new device PID" +labels: ["Device Support"] +body: + - type: markdown + attributes: + value: | + 👆 Please substitute the device name in the title above. + + ## Before you continue... + + [🔍 Search for existing issues and pull requests](https://github.com/openrazer/openrazer/issues?q=label%3A%22Device+Support%22) by searching for your USB PID. Please avoid creating duplicates. + + You can get your USB PID by running `lsusb` in a terminal: + + ```shell + lsusb | grep 1532 + ``` + + For example, if you see `1532:0203`, your device PID is `0203`. + + Your device may have different PIDs depending if it's wired or wireless, so check those too. + + If the issue is closed, or the pull request is merged (purple), your device is supported in the next release. [Check the comparison](https://github.com/openrazer/openrazer/compare/stable...master) to see if that's the case! + + ## For new devices + + - type: input + id: device_name + attributes: + label: "Device Name" + description: Check the sticker under the device. + placeholder: Razer BlackWidow Chroma + validations: + required: true + + - type: input + id: product_number + attributes: + label: "Product Number" + description: Check the sticker under the device. + placeholder: RZ03-01220300 + validations: + required: true + + - type: input + id: model_number + attributes: + label: "Model Number" + description: Check the sticker under the device. + placeholder: RZ03-0122 + validations: + required: true + + - type: input + id: device_pid + attributes: + label: "VID:PID" + description: "Run 'lsusb' in a terminal. Enter the ID seen before the device name." + placeholder: "1532:0203" + validations: + required: true + + - type: textarea + id: lsusb_output + attributes: + label: "USB Details" + description: "Paste the output of this command: lsusb -d 1532: -v" + render: shell + validations: + required: true + + - type: textarea + id: sysfs_output + attributes: + label: "Device Input Paths" + description: "Paste the output of this command: ls -lah /dev/input/by-id/" + render: shell + validations: + required: true + + - type: textarea + id: usbhid_dump_output + attributes: + label: "USB HID Dump" + description: "Paste the output of this command: usbhid-dump -m 1532 -ed" + render: shell + validations: + required: false + + - type: textarea + id: packet_captures + attributes: + label: "Packet Captures" + description: "To analyse the communication and protocol required for this device. See here on capturing this: https://github.com/openrazer/openrazer/wiki/Reverse-Engineering-USB-Protocol" + placeholder: "Drag and drop to upload files" + validations: + required: false + + - type: textarea + id: synapse_screenshots + attributes: + label: "Synapse Screenshots" + description: "Please take screenshots of all available options in Razer Synapse from a Windows environment." + placeholder: "Drag and drop to upload images" + validations: + required: false diff --git a/openrazer/.github/ISSUE_TEMPLATE/01-support.yml b/openrazer/.github/ISSUE_TEMPLATE/01-support.yml new file mode 100644 index 00000000..160e8ac4 --- /dev/null +++ b/openrazer/.github/ISSUE_TEMPLATE/01-support.yml @@ -0,0 +1,74 @@ +name: "Report a problem or support request" +description: "The driver, daemon or my device isn't working as expected" +labels: ["support"] +body: + - type: input + id: device_name + attributes: + label: "Affected Device / PID" + description: + placeholder: "Razer BlackWidow Chroma, 1532:0203" + validations: + required: true + + - type: input + id: distro_version + attributes: + label: "Operating System / Version" + placeholder: "Ubuntu 24.04" + validations: + required: true + + - type: input + id: kernel_version + attributes: + label: "Kernel Version" + description: "Run 'uname -r' in a terminal." + placeholder: "6.8.0-39-generic" + validations: + required: true + + - type: input + id: openrazer_version + attributes: + label: "OpenRazer Version" + description: + placeholder: "3.7.0" + validations: + required: true + + - type: checkboxes + id: declaration + attributes: + label: "Support Checklist" + description: "Please check before submitting:" + options: + - label: "My user was added to the plugdev group." + required: true + - label: "I have rebooted and the problem persists." + required: true + - label: "I looked at the [Troubleshooting](https://github.com/openrazer/openrazer/wiki/Troubleshooting) page and it did not solve the problem." + required: true + + - type: checkboxes + id: checklist + attributes: + label: Symptoms + description: "Do any of these apply?" + options: + - label: "Uninstalling OpenRazer fixes the problem" + - label: "Re-plugging the device fixes the problem" + - label: "It worked before a system/kernel update." + - label: "Only a problem if the daemon is running." + - label: "Only a problem from power up or a reboot." + - label: "I'm dual booting with Windows." + - label: "Intermittent or erratic problem." + - label: "My device is missing a feature." + + - type: textarea + id: description + attributes: + label: "Please describe the issue" + description: "Include any logs (in code blocks) if necessary." + validations: + required: true diff --git a/openrazer/.github/ISSUE_TEMPLATE/config.yml b/openrazer/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..7be82237 --- /dev/null +++ b/openrazer/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,13 @@ +blank_issues_enabled: true +contact_links: + - name: ⚠️ Installation not working? + url: https://github.com/openrazer/openrazer/wiki/Troubleshooting + about: The troubleshooting guide covers most common problems + + - name: 🗨️ Ask the Community Chat on Telegram + url: https://t.me/joinchat/AMhHjj9Txhkhn8JM5_LeMg + about: OpenRazer General + + - name: 🗨️ Ask the Community Chat on Matrix + url: https://matrix.to/#/#openrazer:matrix.org + about: Bridged with the Telegram chat diff --git a/openrazer/.github/workflows/stale.yml b/openrazer/.github/workflows/stale.yml new file mode 100644 index 00000000..8643cf7a --- /dev/null +++ b/openrazer/.github/workflows/stale.yml @@ -0,0 +1,22 @@ +name: Mark stale issues +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + actions: write + steps: + - uses: actions/stale@v9 + with: + stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + days-before-issue-stale: 120 + days-before-issue-close: 30 + days-before-pr-stale: -1 + days-before-pr-close: -1 + stale-issue-label: 'wontfix' + exempt-issue-labels: 'Device Support,not stale' diff --git a/openrazer/.gitignore b/openrazer/.gitignore new file mode 100644 index 00000000..12671de3 --- /dev/null +++ b/openrazer/.gitignore @@ -0,0 +1,67 @@ +pylib/docs/_build + +# pytest caches +.pytest_cache/ + +# Object files +*.o +*.do +*.da +*.ko +*.obj +*.elf +*.o.d + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# kdevelop files +.kdev4/* +*.kdev4 + +# vim temp files +*.un~ +*~ +*.swp + +# clion files +cmake-build-debug/* +compile_commands.json + +# Cached/Pre-compiled Python files +*.pyc +__pycache__ + +dist +.idea +.project +.cproject +*.o.cmd +*.ko.cmd +/driver/.tmp_versions +/driver/Module.symvers +/driver/modules.order +/driver/*.mod +/driver/*.mod.c +/driver/.*.cmd diff --git a/openrazer/.mailmap b/openrazer/.mailmap new file mode 100644 index 00000000..e6374d56 --- /dev/null +++ b/openrazer/.mailmap @@ -0,0 +1,4 @@ +Terri Cain +Terri Cain +Luca Weiss +Luca Weiss diff --git a/openrazer/DEVELOPMENT.md b/openrazer/DEVELOPMENT.md new file mode 100644 index 00000000..cbcaefcb --- /dev/null +++ b/openrazer/DEVELOPMENT.md @@ -0,0 +1,168 @@ +# Development + +## Introduction + +OpenRazer consists of a Linux kernel module and Python daemon + library. The Linux kernel module exposes an +sysfs interface, the Python daemon (openrazer-daemon) exposes this on it's turn over D-Bus. + +It also includes Python libraries for applications and scripts to use that communicate to the daemon over D-Bus. + +## Add New Device Support + +If you want to add support for a new hardware device it's often required to make changes to both the kernel module (`driver/`) and the Python sources (`daemon/`). + +First of all, **there's no need to reinvent the wheel**. Based on the type of device you're adding, look for relevant pull requests, where similar devices have already been integrated. + +Basic steps though, are: + +1. Connect the device then run: `lsusb` to find the connected device's Vendor & Product IDs. +
e.g. `Bus 003 Device 012: ID 1532:0c05 Razer USA, Ltd Razer Strider Chroma` +
**VID (vendor ID):** 1532 +
**PID (product ID):** 0c05 +2. Open **README.md** and append the new device, *ordered by type and by VID:PID* +3. Go to `daemon/openrazer_daemon/hardware/[device_type].py` +
`[device_type]`: file according to your device type, and create the device class. Use other devices as referece. In addition, **search for the device's specs before that**, e.g. Matrix of LEDs, images from official Razer site, methods etc, to configure the device properly. +4. Go to: `driver/razer[device_type]_driver.h` to define a constant that points to the device's PID as **0x[PID]** +
e.g. for the previous device: `#define USB_DEVICE_ID_RAZER_STRIDER_CHROMA 0x0C05` +
(Note: *keep using the correct order while defining or using VIDs or PIDs, as mentioned above*) +5. Go to `driver/razer[device_type]_driver.c` and add support in the kernel driver for the device. Here you can provide functionality to communicate with the USB device, manage its features & effects, and expose device-specific attributes through sysfs. +6. Last (but not least) navigate to: `install_files/udev/99-razer.rules` to append the device's PID (always in correct order - as we said), in the correct ruleset. +7. Run: `./scripts/format_source.sh` in case you have any linting issues. +8. Run: `./scripts/generate_appstream_file.sh` to generate the `install_files/appstream/io.github.openrazer.openrazer.metainfo.xml` +9. Run: `./scripts/generate_all_fake_drivers.sh -f` to generate `pylib/openrazer/_fake_driver/*.cfg` + +This description assumes you have cloned the openrazer repository to your home directory, also created a new branch e.g. **add-[device_name]-support**. + +Test thoroughly, then open a PR. Don't forget to link related issues resolved to your PR, also write a description of what is implemented, tested and working, also what is not working. + +## Setup your development environment + +These instructions should help you setup a development environment for both the kernel module and Python +daemon. + +### Kernel module + +It is possible to do development and test your changes on your local system but you risk kernel panics and therefore +possibly some data loss. Therefore it's recommended to do your development on a separate virtual or physical machine. + +When you forward a USB device to the virtual machine, it becomes inaccessible for the host, so if you forward your +keyboard make sure you have a second one attached so you can still control your host. + +I had some success with QEMU on Linux with the following. + +To add a device to QEMU (change hostbus/hostaddr to the Razer device): +``` +device_add usb-host,id=razer,hostbus=5,hostaddr=2 +``` + +and to remove the device from the virtual machine: +``` +device_del razer +``` + +If you're on macOS or Windows I recommend to use VirtualBox and use USB passthough as described here: +[VirtualBox USB Support](https://www.virtualbox.org/manual/ch03.html#settings-usb) + +Make sure you're using the same kernel version on both your development as your test machine. Easiest way +to achieve this is to use the same Linux distribution and use the latest available kernel version. + +#### Debian/Ubuntu + +For Debian/Ubuntu install the following packages for kernel development: + +``` +apt-get install -y make gcc flex bison bc linux-headers-$(uname -r) +``` + +#### RedHat/Fedora + +For RedHat/Fedora install the following packages for kernel development: + +``` +dnf install -y binutils make gcc ncurses-devel sed flex bison kernel-headers +``` + +#### Build the kernel module + +Run the following command to build the kernel module: + +``` +make driver +``` + +This will build the kernel modules in `driver/*.ko`. If you make changes to the sources +you can rerun the `make driver` command and the modules will be rebuild. + + +#### Test the kernel module + +You can copy the `driver/*.ko` modules to your test system and (re)load for example +the keyboard module using: + +``` +rmmod razerkbd && insmod razerkbd.ko +``` + +If you update the kernel module you have to manually reload the module. + +Driver messages can be found by running: + +``` +dmesg +``` + +### Python daemon + +OpenRazer can only use your system site-packages and cannot be (easily) installed in +a virtualenv. Therefore you will have to install the dependencies on your system and +set your PYTHONPATH so you can run from sources. + +#### Debian/Ubuntu + +For Debian/Ubuntu install the following packages to be able to run the daemon: + +``` +apt-get install -y libnotify-bin python3 python3-daemonize python3-dbus python3-gi python3-numpy python3-pyudev python3-setproctitle +``` + +#### RedHat/Fedora + +For RedHat/Fedora install the following packages to be able to run the daemon: + +``` +dnf install -y libnotify python3 python3-daemonize python3-dbus python3-numpy python3-pyudev python3-setproctitle +``` + +#### Test the daemon + +Copy or have another clone of openrazer on your test system. + +Run: + +``` +PYTHONPATH="pylib:daemon" python3 ./daemon/run_openrazer_daemon.py -Fv --config=$PWD/daemon/resources/razer.conf +``` + +## Contribute back your changes! + +### Prerequisites + +The OpenRazer code is licensed under the GPL-2.0-or-later license. Make sure you understand what this means. Please +also be sure that if your changes include work done by others they also agree with publishing under this license. + +If you haven't already you'll have to sign up for a GitHub account, fork this repository and push your changes to a +branch in this fork. + +### Check if there's a issue for what you've fixed + +Please search our issues to see if you've fixed something that has been reported by someone already. If you're +adding support for a new device please create a new github issue. + +### Create a new pull request + +[Create a new pull request](https://github.com/openrazer/openrazer/compare) and please properly describe your changes. + +Keep in mind, OpenRazer is an open source project managed by volunteers, we really appreciate your work but +everything is done as a best effort. + +Even if your changes work we could decide they're not suitable for OpenRazer or require changes. diff --git a/openrazer/LICENSES/CC-BY-SA-4.0.txt b/openrazer/LICENSES/CC-BY-SA-4.0.txt new file mode 100644 index 00000000..835a6836 --- /dev/null +++ b/openrazer/LICENSES/CC-BY-SA-4.0.txt @@ -0,0 +1,170 @@ +Creative Commons Attribution-ShareAlike 4.0 International + + Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. + +Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. + +Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. + +Creative Commons Attribution-ShareAlike 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + + a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + + e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + + i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + + k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; and + + B. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. + + C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + b. ShareAlike.In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + 1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; + + b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + + a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + + b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + + c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + + a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + + d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + + e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + + a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + + c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + + d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/openrazer/LICENSES/GPL-2.0-or-later.txt b/openrazer/LICENSES/GPL-2.0-or-later.txt new file mode 100644 index 00000000..17cb2864 --- /dev/null +++ b/openrazer/LICENSES/GPL-2.0-or-later.txt @@ -0,0 +1,117 @@ +GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. + + c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. + +signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice diff --git a/openrazer/Makefile b/openrazer/Makefile new file mode 100644 index 00000000..14bb6797 --- /dev/null +++ b/openrazer/Makefile @@ -0,0 +1,134 @@ +# ********************************* WARNING ********************************* +# This Makefile is not supposed to be used outside of certain usecases like +# compiling the driver ("make driver") in this repository or installing the +# files as part of distribution packaging. +# +# Please never run the install targets manually (unless you really know what +# you're doing) as they're not intended to be used like that! +# +# You're in nearly all cases better off following the build instructions +# that you can find in the wiki. +# *************************************************************************** + +# PREFIX is used to prefix where the files will be installed under DESTDIR +PREFIX?=/usr +# UDEV_PREFIX is specifically a prefix for udev files +UDEV_PREFIX?=$(PREFIX) +# DESTDIR is used to install into a different root directory +DESTDIR?=/ +# Specify the kernel directory to use +KERNELDIR?=/lib/modules/$(shell uname -r)/build +# Need the absolute directory do the driver directory to build kernel modules +DRIVERDIR?=$(shell pwd)/driver + +# Where kernel drivers are going to be installed +MODULEDIR?=/lib/modules/$(shell uname -r)/kernel/drivers/hid + +DKMS_NAME?=openrazer-driver +DKMS_VER?=3.10.3 + + +# Build all target +all: driver + +# Driver compilation +driver: + @echo -e "\n::\033[32m Compiling OpenRazer kernel modules\033[0m" + @echo "========================================" + $(MAKE) -C $(KERNELDIR) M=$(DRIVERDIR) modules + +driver_clean: + @echo -e "\n::\033[32m Cleaning OpenRazer kernel modules\033[0m" + @echo "========================================" + $(MAKE) -C "$(KERNELDIR)" M="$(DRIVERDIR)" clean + +# Install kernel modules and then update module dependencies +driver_install: + @echo -e "\n::\033[34m Installing OpenRazer kernel modules\033[0m" + @echo "=====================================================" + @cp -v $(DRIVERDIR)/*.ko $(DESTDIR)/$(MODULEDIR) + @chown -v root:root $(DESTDIR)/$(MODULEDIR)/*.ko + depmod + +# Just use for packaging openrazer, not for installing manually +driver_install_packaging: + @echo -e "\n::\033[34m Installing OpenRazer kernel modules\033[0m" + @echo "=====================================================" + @cp -v $(DRIVERDIR)/*.ko $(DESTDIR)/$(MODULEDIR) + +# Razer Daemon +daemon_install: + @echo -e "\n::\033[34m Installing OpenRazer Daemon\033[0m" + @echo "=====================================================" + make --no-print-directory -C daemon install + +ubuntu_daemon_install: + @echo -e "\n::\033[34m Installing OpenRazer Daemon\033[0m" + @echo "=====================================================" + make --no-print-directory -C daemon ubuntu_install + +# Python Library +python_library_install: + @echo -e "\n::\033[34m Installing OpenRazer python library\033[0m" + @echo "=====================================================" + @make --no-print-directory -C pylib install + +ubuntu_python_library_install: + @echo -e "\n::\033[34m Installing OpenRazer python library\033[0m" + @echo "=====================================================" + @make --no-print-directory -C pylib ubuntu_install + +# Legacy XDG autostart +xdg_install: + @mkdir -p $(DESTDIR)/etc/xdg/autostart + @cp -v ./install_files/desktop/openrazer-daemon.desktop $(DESTDIR)/etc/xdg/autostart/openrazer-daemon.desktop + +install-systemd: + @make --no-print-directory -C daemon install-systemd + +# Clean target +clean: driver_clean + +setup_dkms: + @echo -e "\n::\033[34m Installing DKMS files\033[0m" + @echo "=====================================================" + install -m 644 -v -D Makefile $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER)/Makefile + install -m 644 -v -D install_files/dkms/dkms.conf $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER)/dkms.conf + install -m 755 -v -d driver $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER)/driver + install -m 644 -v -D driver/Makefile $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER)/driver/Makefile + install -m 644 -v driver/*.c $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER)/driver/ + install -m 644 -v driver/*.h $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER)/driver/ + rm -fv $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER)/driver/*.mod.c + +remove_dkms: + @echo -e "\n::\033[34m Removing DKMS files\033[0m" + @echo "=====================================================" + rm -rf $(DESTDIR)$(PREFIX)/src/$(DKMS_NAME)-$(DKMS_VER) + +udev_install: + @echo -e "\n::\033[34m Installing OpenRazer udev rules\033[0m" + @echo "=====================================================" + install -m 644 -v -D install_files/udev/99-razer.rules $(DESTDIR)$(UDEV_PREFIX)/lib/udev/rules.d/99-razer.rules + install -m 755 -v -D install_files/udev/razer_mount $(DESTDIR)$(UDEV_PREFIX)/lib/udev/razer_mount + +appstream_install: + @echo -e "\n::\033[34m Installing OpenRazer AppStream metadata\033[0m" + @echo "=====================================================" + install -m 644 -v -D install_files/appstream/io.github.openrazer.openrazer.metainfo.xml $(DESTDIR)$(PREFIX)/share/metainfo/io.github.openrazer.openrazer.metainfo.xml + +# Install for Ubuntu +# WARNING: do not use this target manually, it is just meant for Debian packaging! Read the warning on top of the file! +ubuntu_install: setup_dkms udev_install ubuntu_daemon_install ubuntu_python_library_install appstream_install + @echo -e "\n::\033[34m Installing for Ubuntu\033[0m" + @echo "=====================================================" + +install_i_know_what_i_am_doing: all driver_install udev_install python_library_install + @make --no-print-directory -C daemon install DESTDIR=$(DESTDIR) + +install: manual_install_msg ; + +manual_install_msg: + @echo "Please do not install the driver using this method. Use a distribution package as it tracks the files installed and can remove them afterwards. If you are 100% sure, you want to do this, find the correct target in the Makefile." + @echo "Exiting." + +.PHONY: driver diff --git a/openrazer/README.md b/openrazer/README.md new file mode 100644 index 00000000..cee67895 --- /dev/null +++ b/openrazer/README.md @@ -0,0 +1,326 @@ +# [OpenRazer](https://openrazer.github.io/) + +A collection of Linux drivers for Razer devices - providing kernel drivers, DBus services and Python bindings to interact with the DBus interface. + +## Something not working? + +Sometimes there are problems with the driver installation due to missing kernel modules or secure boot. Please refer to the [Troubleshooting wiki page](https://github.com/openrazer/openrazer/wiki/Troubleshooting) for guidance. + +If the troubleshooting guide did not pinpoint the problem, [try searching open/closed issues](https://github.com/openrazer/openrazer/issues?q=is%3Aissue+) before creating a new one. + +## Device Support + +The list below contains latest devices supported on this branch (usually **master**). These might not be released yet, so check the [stable branch](https://github.com/openrazer/openrazer/tree/stable) for what should be available in the packages for your distribution. + +The devices below are fully feature supported by OpenRazer, which means all available USB controllable functions for that product are made available by the library. + +### Keyboards +| Device | USB VID:PID | +| --------------------------------------------- | ----------- | +| Razer BlackWidow Ultimate 2012 | 1532:010D | +| Razer BlackWidow Classic (Alternate) | 1532:010E | +| Razer Anansi | 1532:010F | +| Razer DeathStalker (Essential) | 1532:0118 | +| Razer BlackWidow Ultimate 2013 | 1532:011A | +| Razer BlackWidow Stealth | 1532:011B | +| Razer BlackWidow Tournament Edition 2014 | 1532:011C | +| Razer DeathStalker Expert | 1532:0202 | +| Razer BlackWidow Chroma | 1532:0203 | +| Razer DeathStalker Chroma | 1532:0204 | +| Razer Blade Stealth | 1532:0205 | +| Razer BlackWidow Tournament Edition Chroma | 1532:0209 | +| Razer Blade QHD | 1532:020F | +| Razer Blade Pro (Late 2016) | 1532:0210 | +| Razer BlackWidow Chroma (Overwatch) | 1532:0211 | +| Razer BlackWidow Ultimate 2016 | 1532:0214 | +| Razer BlackWidow X Chroma | 1532:0216 | +| Razer BlackWidow X Ultimate | 1532:0217 | +| Razer BlackWidow X Tournament Edition Chroma | 1532:021A | +| Razer Ornata Chroma | 1532:021E | +| Razer Ornata | 1532:021F | +| Razer Blade Stealth (Late 2016) | 1532:0220 | +| Razer BlackWidow Chroma V2 | 1532:0221 | +| Razer Blade (Late 2016) | 1532:0224 | +| Razer Blade Pro (2017) | 1532:0225 | +| Razer Huntsman Elite | 1532:0226 | +| Razer Huntsman | 1532:0227 | +| Razer BlackWidow Elite | 1532:0228 | +| Razer Cynosa Chroma | 1532:022A | +| Razer Cynosa Chroma Pro | 1532:022C | +| Razer Blade Stealth (Mid 2017) | 1532:022D | +| Razer Blade Pro FullHD (2017) | 1532:022F | +| Razer Blade Stealth (Late 2017) | 1532:0232 | +| Razer Blade 15 (2018) | 1532:0233 | +| Razer Blade Pro 17 (2019) | 1532:0234 | +| Razer BlackWidow Lite (2018) | 1532:0235 | +| Razer BlackWidow Essential | 1532:0237 | +| Razer Blade Stealth (2019) | 1532:0239 | +| Razer Blade 15 Advanced (2019) | 1532:023A | +| Razer Blade 15 Base (2018) | 1532:023B | +| Razer Cynosa Lite | 1532:023F | +| Razer Blade 15 Mercury (2018) | 1532:0240 | +| Razer BlackWidow (2019) | 1532:0241 | +| Razer Huntsman Tournament Edition | 1532:0243 | +| Razer Blade 15 Mercury (Mid 2019) | 1532:0245 | +| Razer Blade 15 Base (Mid 2019) | 1532:0246 | +| Razer Blade Stealth (Late 2019) | 1532:024A | +| Razer Blade Advanced (Late 2019) | 1532:024B | +| Razer Blade Pro (Late 2019) | 1532:024C | +| Razer Blade 15 Studio Edition (2019) | 1532:024D | +| Razer BlackWidow V3 | 1532:024E | +| Razer Blade Stealth (Early 2020) | 1532:0252 | +| Razer Blade 15 Advanced (2020) | 1532:0253 | +| Razer Blade 15 Base (Early 2020) | 1532:0255 | +| Razer Blade Pro 17 (Early 2020) | 1532:0256 | +| Razer Huntsman Mini | 1532:0257 | +| Razer BlackWidow V3 Mini Hyperspeed (Wired) | 1532:0258 | +| Razer Blade Stealth (Late 2020) | 1532:0259 | +| Razer BlackWidow V3 Pro (Wired) | 1532:025A | +| Razer BlackWidow V3 Pro (Wireless) | 1532:025C | +| Razer Ornata V2 | 1532:025D | +| Razer Cynosa V2 | 1532:025E | +| Razer Huntsman V2 Analog | 1532:0266 | +| Razer Blade 15 Base (Late 2020) | 1532:0268 | +| Razer Huntsman Mini (JP) | 1532:0269 | +| Razer Book 13 (2020) | 1532:026A | +| Razer Huntsman V2 TKL | 1532:026B | +| Razer Huntsman V2 | 1532:026C | +| Razer Blade 15 Advanced (Early 2021) | 1532:026D | +| Razer Blade 17 Pro (Early 2021) | 1532:026E | +| Razer Blade 15 Base (Early 2021) | 1532:026F | +| Razer Blade 14 (2021) | 1532:0270 | +| Razer BlackWidow V3 Mini Hyperspeed (Wireless)| 1532:0271 | +| Razer Blade 15 Advanced (Mid 2021) | 1532:0276 | +| Razer Blade 17 Pro (Mid 2021) | 1532:0279 | +| Razer Blade 15 Base (2022) | 1432:027A | +| Razer Huntsman Mini Analog | 1532:0282 | +| Razer BlackWidow V4 | 1532:0287 | +| Razer Blade 15 Advanced (Early 2022) | 1532:028A | +| Razer Blade 17 (2022) | 1532:028B | +| Razer Blade 14 (2022) | 1532:028C | +| Razer BlackWidow V4 Pro | 1532:028D | +| Razer Ornata V3 | 1532:028F | +| Razer DeathStalker V2 Pro (Wireless) | 1532:0290 | +| Razer DeathStalker V2 Pro (Wired) | 1532:0292 | +| Razer BlackWidow V4 X | 1532:0293 | +| Razer Ornata V3 X | 1532:0294 | +| Razer DeathStalker V2 Pro TKL (Wireless) | 1532:0296 | +| Razer DeathStalker V2 Pro TKL (Wired) | 1532:0298 | +| Razer DeathStalker V2 | 1532:0295 | +| Razer Blade 14 (2023) | 1532:029D | +| Razer Blade 15 (2023) | 1532:029E | +| Razer Blade 16 (2023) | 1532:029F | +| Razer Blade 18 (2023) | 1532:02A0 | +| Razer Ornata V3 | 1532:02A1 | +| Razer Ornata V3 X | 1532:02A2 | +| Razer Ornata V3 Tenkeyless | 1532:02A3 | +| Razer BlackWidow V4 75% | 1532:02A5 | +| Razer Huntsman V3 Pro | 1532:02A6 | +| Razer Blade 14 (2024) | 1532:02B6 | +| Razer Blade 18 (2024) | 1532:02B8 | +| Razer Blade 16 (2025) | 1532:02C6 | +| Razer BlackWidow V3 Tenkeyless | 1532:0A24 | + +### Mice +| Device | USB VID:PID | +| --------------------------------------------- | ----------- | +| Razer Orochi 2011 | 1532:0013 | +| Razer Naga | 1532:0015 | +| Razer DeathAdder 3.5G | 1532:0016 | +| Razer Naga Epic | 1532:001F | +| Razer Abyssus 1800 | 1532:0020 | +| Razer Mamba 2012 (Wired) | 1532:0024 | +| Razer Mamba 2012 (Wireless) | 1532:0025 | +| Razer DeathAdder 3.5G Black | 1532:0029 | +| Razer Naga 2012 | 1532:002E | +| Razer Imperator 2012 | 1532:002F | +| Razer Ouroboros 2012 | 1532:0032 | +| Razer Taipan | 1532:0034 | +| Razer Naga Hex (Red) | 1532:0036 | +| Razer DeathAdder 2013 | 1532:0037 | +| Razer DeathAdder 1800 | 1532:0038 | +| Razer Orochi 2013 | 1532:0039 | +| Razer Naga Epic Chroma (Wired) | 1532:003E | +| Razer Naga Epic Chroma (Wireless) | 1532:003F | +| Razer Naga 2014 | 1532:0040 | +| Razer Naga Hex | 1532:0041 | +| Razer Abyssus 2014 | 1532:0042 | +| Razer DeathAdder Chroma | 1532:0043 | +| Razer Mamba (Wired) | 1532:0044 | +| Razer Mamba (Wireless) | 1532:0045 | +| Razer Mamba Tournament Edition | 1532:0046 | +| Razer Orochi (Wired) | 1532:0048 | +| Razer Diamondback Chroma | 1532:004C | +| Razer DeathAdder 2000 | 1532:004F | +| Razer Naga Hex V2 | 1532:0050 | +| Razer Naga Chroma | 1532:0053 | +| Razer DeathAdder 3500 | 1532:0054 | +| Razer Lancehead (Wired) | 1532:0059 | +| Razer Lancehead (Wireless) | 1532:005A | +| Razer Abyssus V2 | 1532:005B | +| Razer DeathAdder Elite | 1532:005C | +| Razer Abyssus 2000 | 1532:005E | +| Razer Lancehead Tournament Edition | 1532:0060 | +| Razer Atheris (Receiver) | 1532:0062 | +| Razer Basilisk | 1532:0064 | +| Razer Basilisk Essential | 1532:0065 | +| Razer Naga Trinity | 1532:0067 | +| Razer Abyssus Elite (D.Va Edition) | 1532:006A | +| Razer Abyssus Essential | 1532:006B | +| Razer Mamba Elite (Wired) | 1532:006C | +| Razer DeathAdder Essential | 1532:006E | +| Razer Lancehead Wireless (Receiver) | 1532:006F | +| Razer Lancehead Wireless (Wired) | 1532:0070 | +| Razer DeathAdder Essential (White Edition) | 1532:0071 | +| Razer Mamba Wireless (Receiver) | 1532:0072 | +| Razer Mamba Wireless (Wired) | 1532:0073 | +| Razer Pro Click (Receiver) | 1532:0077 | +| Razer Viper | 1532:0078 | +| Razer Viper Ultimate (Wired) | 1532:007A | +| Razer Viper Ultimate (Wireless) | 1532:007B | +| Razer DeathAdder V2 Pro (Wired) | 1532:007C | +| Razer DeathAdder V2 Pro (Wireless) | 1532:007D | +| Razer Pro Click (Wired) | 1532:0080 | +| Razer Basilisk X HyperSpeed | 1532:0083 | +| Razer DeathAdder V2 | 1532:0084 | +| Razer Basilisk V2 | 1532:0085 | +| Razer Basilisk Ultimate (Wired) | 1532:0086 | +| Razer Basilisk Ultimate (Receiver) | 1532:0088 | +| Razer Viper Mini | 1532:008A | +| Razer DeathAdder V2 Mini | 1532:008C | +| Razer Naga Left-Handed Edition | 1532:008D | +| Razer Naga Pro (Wired) | 1532:008F | +| Razer Naga Pro (Wireless) | 1532:0090 | +| Razer Viper 8KHz | 1532:0091 | +| Razer Orochi V2 (Receiver) | 1532:0094 | +| Razer Orochi V2 (Bluetooth) | 1532:0095 | +| Razer Naga X | 1532:0096 | +| Razer DeathAdder Essential (2021) | 1532:0098 | +| Razer Basilisk V3 | 1532:0099 | +| Razer Pro Click Mini (Receiver) | 1532:009A | +| Razer DeathAdder V2 X HyperSpeed | 1532:009C | +| Razer Viper Mini Signature Edition (Wired) | 1532:009E | +| Razer Viper Mini Signature Edition (Wireless) | 1532:009F | +| Razer DeathAdder V2 Lite | 1532:00A1 | +| Razer Cobra | 1532:00A3 | +| Razer Viper V2 Pro (Wired) | 1532:00A5 | +| Razer Viper V2 Pro (Wireless) | 1532:00A6 | +| Razer Naga V2 Pro (Wired) | 1532:00A7 | +| Razer Naga V2 Pro (Wireless) | 1532:00A8 | +| Razer Basilisk V3 Pro (Wired) | 1532:00AA | +| Razer Basilisk V3 Pro (Wireless) | 1532:00AB | +| Razer Cobra Pro (Wired) | 1532:00AF | +| Razer Cobra Pro (Wireless) | 1532:00B0 | +| Razer DeathAdder V3 | 1532:00B2 | +| Razer HyperPolling Wireless Dongle | 1532:00B3 | +| Razer Naga V2 HyperSpeed (Receiver) | 1532:00B4 | +| Razer DeathAdder V3 Pro (Wired) | 1532:00B6 | +| Razer DeathAdder V3 Pro (Wireless) | 1532:00B7 | +| Razer Viper V3 HyperSpeed | 1532:00B8 | +| Razer Basilisk V3 X HyperSpeed | 1532:00B9 | +| Razer Viper V3 Pro (Wired) | 1532:00C0 | +| Razer Viper V3 Pro (Wireless) | 1532:00C1 | +| Razer DeathAdder V3 Pro (Wired) | 1532:00C2 | +| Razer DeathAdder V3 Pro (Wireless) | 1532:00C3 | +| Razer DeathAdder V3 HyperSpeed (Wired) | 1532:00C4 | +| Razer DeathAdder V3 HyperSpeed (Wireless) | 1532:00C5 | +| Razer Pro Click V2 Vertical Edition (Wired) | 1532:00C7 | +| Razer Pro Click V2 Vertical Edition (Wireless)| 1532:00C8 | +| Razer Basilisk V3 35K | 1532:00CB | +| Razer Basilisk V3 Pro 35K (Wired) | 1532:00CC | +| Razer Basilisk V3 Pro 35K (Wireless) | 1532:00CD | + +### Mousemats +| Device | USB VID:PID | +| --------------------------------------------- | ----------- | +| Razer Firefly Hyperflux | 1532:0068 | +| Razer Firefly | 1532:0C00 | +| Razer Goliathus | 1532:0C01 | +| Razer Goliathus Extended | 1532:0C02 | +| Razer Firefly V2 | 1532:0C04 | +| Razer Strider Chroma | 1532:0C05 | +| Razer Goliathus Chroma 3XL | 1532:0C06 | +| Razer Firefly V2 Pro | 1532:0C08 | + +### Headsets +| Device | USB VID:PID | +| --------------------------------------------- | ----------- | +| Razer Kraken 7.1 | 1532:0501 | +| Razer Kraken 7.1 Chroma | 1532:0504 | +| Razer Kraken 7.1 | 1532:0506 | +| Razer Kraken 7.1 V2 | 1532:0510 | +| Razer Kraken Ultimate | 1532:0527 | +| Razer Kraken Kitty Edition V2 | 1532:0560 | +| Razer Kraken Kitty Edition | 1532:0F19 | + +### Misc +| Device | USB VID:PID | +| --------------------------------------------- | ----------- | +| Razer Mouse Dock | 1532:007E | +| Razer Nostromo | 1532:0111 | +| Razer Orbweaver | 1532:0113 | +| Razer Tartarus | 1532:0201 | +| Razer Orbweaver Chroma | 1532:0207 | +| Razer Tartarus Chroma | 1532:0208 | +| Razer Core | 1532:0215 | +| Razer Tartarus V2 | 1532:022B | +| Razer Nommo Chroma | 1532:0517 | +| Razer Nommo Pro | 1532:0518 | +| Razer Chroma Mug Holder | 1532:0F07 | +| Razer Base Station Chroma | 1532:0F08 | +| Razer Chroma Hardware Development Kit (HDK) | 1532:0F09 | +| Razer Laptop Stand Chroma | 1532:0F0D | +| Razer Raptor 27 | 1532:0F12 | +| Razer Core X Chroma | 1532:0F1A | +| Razer Mouse Bungee V3 Chroma | 1532:0F1D | +| Razer Chroma Addressable RGB Controller | 1532:0F1F | +| Razer Base Station V2 Chroma | 1532:0F20 | +| Razer Thunderbolt 4 Dock Chroma | 1532:0F21 | +| Razer Charging Pad Chroma | 1532:0F26 | +| Razer Laptop Stand Chroma V2 | 1532:0F2B | + +#### Determining the Device ID +Razer devices use a USB VID (Vendor ID) of `1532`. You can identify the USB PID (Product ID) by typing: + + lsusb | grep '1532:' + +This will output something similar to this: + + Bus 003 Device 005: ID 1532:0203 Razer USA, Ltd + + +--- + +## Installation + +Official packages are available for these distributions (and their derivatives): + +* [Debian](https://openrazer.github.io/#debian) +* [Fedora](https://openrazer.github.io/#fedora) +* [Mageia](https://openrazer.github.io/#mageia) +* [openSUSE](https://openrazer.github.io/#opensuse) +* [Ubuntu](https://openrazer.github.io/#ubuntu) + +Community supported packages are available for: + +* [Alpine Linux](https://openrazer.github.io/#alpine) +* [Arch Linux](https://openrazer.github.io/#arch) +* [Gentoo](https://openrazer.github.io/#gentoo) +* [NixOS](https://openrazer.github.io/#nixos) +* [Slackware](https://openrazer.github.io/#slackware) +* [Solus](https://openrazer.github.io/#solus) +* [Void Linux](https://openrazer.github.io/#voidlinux) + +## Applications + +The following applications complement and interact with this driver: + +* [Polychromatic](https://github.com/polychromatic/polychromatic) - a graphical management tool and tray applet to managing Razer peripherals. +* [RazerGenie](https://github.com/z3ntu/RazerGenie) - Qt application for configuring your Razer devices under GNU/Linux. +* [razerCommander](https://github.com/GabMus/razerCommander) - Simple GUI written in Gtk3 +* [Snake](http://bithatch.co.uk/snake.html) - a stylised tool and tray applet for configuring Razer devices on Linux, written in Java. +* [Chroma Feedback](https://github.com/redaxmedia/chroma-feedback) - Turn your Razer keyboard, mouse or headphone into a extreme feedback device + +--- + +The project is licensed under the GPL and is not officially endorsed by [Razer, Inc](http://www.razerzone.com/). diff --git a/openrazer/daemon/Makefile b/openrazer/daemon/Makefile new file mode 100644 index 00000000..abad402d --- /dev/null +++ b/openrazer/daemon/Makefile @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +DESTDIR?=/ +PREFIX?=/usr + +purge_pycache: + @find -name '__pycache__' | xargs rm -rf + +service: + @sed "s|##PREFIX##|$(PREFIX)|" resources/org.razer.service.in > org.razer.service + @sed "s|##PREFIX##|$(PREFIX)|" resources/openrazer-daemon.systemd.service.in > openrazer-daemon.service + +install-resources: service + @install -m 644 -D -v resources/razer.conf $(DESTDIR)$(PREFIX)/share/openrazer/razer.conf.example + @install -m 755 -D -v run_openrazer_daemon.py $(DESTDIR)$(PREFIX)/bin/openrazer-daemon + +install-systemd: service + @install -m 644 -D -v org.razer.service $(DESTDIR)$(PREFIX)/share/dbus-1/services/org.razer.service + @install -m 644 -D -v openrazer-daemon.service $(DESTDIR)$(PREFIX)/lib/systemd/user/openrazer-daemon.service + +install: purge_pycache manpages install-resources install-systemd + python3 setup.py install --prefix=$(PREFIX) --root=$(DESTDIR) + +ubuntu_install: purge_pycache manpages install-resources + python3 setup.py install --prefix=$(PREFIX) --root=$(DESTDIR) --no-compile --install-layout=deb + +manpages: + @install -m 644 -D -v resources/man/razer.conf.5 $(DESTDIR)$(PREFIX)/share/man/man5/razer.conf.5 + @gzip -n $(DESTDIR)$(PREFIX)/share/man/man5/razer.conf.5 + @install -m 644 -D -v resources/man/openrazer-daemon.8 $(DESTDIR)$(PREFIX)/share/man/man8/openrazer-daemon.8 + @gzip -n $(DESTDIR)$(PREFIX)/share/man/man8/openrazer-daemon.8 diff --git a/openrazer/daemon/openrazer_daemon/__init__.py b/openrazer/daemon/openrazer_daemon/__init__.py new file mode 100644 index 00000000..4dbf6929 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/__init__.py @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Razer Daemon module +""" diff --git a/openrazer/daemon/openrazer_daemon/daemon.py b/openrazer/daemon/openrazer_daemon/daemon.py new file mode 100644 index 00000000..55fdd624 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/daemon.py @@ -0,0 +1,654 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Daemon class + +This class is the main core of the daemon, this serves a basic dbus module to control the main bit of the daemon +""" +__version__ = '3.10.3' + +import configparser +import logging +import logging.handlers +import os +import sys +import signal +import time +import setproctitle +import dbus.mainloop.glib +import dbus.service +from gi.repository import GLib +from pyudev import Context, Monitor, MonitorObserver +import grp +import getpass +import json +import threading + +import openrazer_daemon.hardware +from openrazer_daemon.dbus_services.service import DBusService +from openrazer_daemon.device import DeviceCollection +from openrazer_daemon.misc.screensaver_monitor import ScreensaverMonitor +from openrazer_daemon.misc.autosave_persistence import PersistenceAutoSave + + +class RazerDaemon(DBusService): + """ + Daemon class + + This class sets up the main run loop which serves DBus messages. The logger is initialised + in this module as well as finding and initialising devices. + + Serves the following functions via DBus + * getDevices - Returns a list of serial numbers + * enableTurnOffOnScreensaver - Starts/Continues the run loop on the screensaver thread + * disableTurnOffOnScreensaver - Pauses the run loop on the screensaver thread + """ + + def __init__(self, verbose=False, log_dir=None, console_log=False, run_dir=None, config_file=None, persistence_file=None, test_dir=None): + + setproctitle.setproctitle('openrazer-daemon') # pylint: disable=no-member + + # Expanding ~ as python doesn't do it by default, also creating dirs if needed + try: + if log_dir is not None: + log_dir = os.path.expanduser(log_dir) + os.makedirs(log_dir, exist_ok=True) + if run_dir is not None: + run_dir = os.path.expanduser(run_dir) + os.makedirs(run_dir, exist_ok=True) + except NotADirectoryError as e: + print("Failed to create {}".format(e.filename), file=sys.stderr) + sys.exit(1) + + if config_file is not None: + config_file = os.path.expanduser(config_file) + if not os.path.exists(config_file): + print("Config file {} does not exist.".format(config_file), file=sys.stderr) + sys.exit(1) + + if persistence_file is not None: + persistence_file = os.path.expanduser(persistence_file) + if not os.path.exists(persistence_file): + print("Persistence file {} does not exist.".format(persistence_file), file=sys.stderr) + sys.exit(1) + + self._test_dir = test_dir + self._run_dir = run_dir + + self._config_file = config_file + self._config = configparser.ConfigParser() + self.read_config(config_file) + + # Logging + log_level = logging.INFO + if verbose or self._config.getboolean('General', 'verbose_logging'): + log_level = logging.DEBUG + self.logger = self._create_logger(log_dir, log_level, console_log) + + self._persistence_file = persistence_file + self._persistence = configparser.ConfigParser() + self._persistence.status = {"changed": False} + self.read_persistence(persistence_file) + + # map of vid+pid to counter for serial numbers for unknown devices + self._unknown_serial_counter: dict[tuple[int, int], int] = {} + + # Check for plugdev group + if not self._check_plugdev_group(): + self.logger.critical("User is not a member of the plugdev group") + self.logger.critical("Please run the command 'sudo gpasswd -a $USER plugdev' and then reboot!") + sys.exit(1) + + # Setup DBus to use gobject main loop + dbus.mainloop.glib.threads_init() + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + super().__init__('/org/razer') + + self._init_signals() + self._main_loop = GLib.MainLoop() + + # Listen for input events from udev + self._init_udev_monitor() + + # Load Classes + self._device_classes = openrazer_daemon.hardware.get_device_classes() + + self.logger.info("Initialising Daemon (v%s). Pid: %d", __version__, os.getpid()) + self._init_screensaver_monitor() + + self._razer_devices = DeviceCollection() + self._load_devices(first_run=True) + + # Add DBus methods + methods = { + # interface, method, callback, in-args, out-args + ('razer.devices', 'getDevices', self.get_serial_list, None, 'as'), + ('razer.devices', 'supportedDevices', self.supported_devices, None, 's'), + ('razer.devices', 'enableTurnOffOnScreensaver', self.enable_turn_off_on_screensaver, 'b', None), + ('razer.devices', 'getOffOnScreensaver', self.get_off_on_screensaver, None, 'b'), + ('razer.devices', 'syncEffects', self.sync_effects, 'b', None), + ('razer.devices', 'getSyncEffects', self.get_sync_effects, None, 'b'), + ('razer.daemon', 'version', self.version, None, 's'), + ('razer.daemon', 'stop', self.stop, None, None), + } + + for m in methods: + self.logger.debug("Adding {}.{} method to DBus".format(m[0], m[1])) + self.add_dbus_method(m[0], m[1], m[2], in_signature=m[3], out_signature=m[4]) + + self._collecting_udev = False + self._collecting_udev_devices = [] + + self._init_autosave_persistence() + + # TODO remove + self.sync_effects(self._config.getboolean('Startup', 'sync_effects_enabled')) + # TODO ====== + + @dbus.service.signal('razer.devices') + def device_removed(self): + self.logger.debug("Emitted Device Remove Signal") + + @dbus.service.signal('razer.devices') + def device_added(self): + self.logger.debug("Emitted Device Added Signal") + + def _create_logger(self, log_dir, log_level, want_console_log): + """ + Initializes a logger and returns it. + + :param log_dir: If not None, specifies the directory to create the + log file in + :param log_level: The log level of messages to print + :param want_console_log: True if we should print to the console + + :rtype:logging.Logger + """ + logger = logging.getLogger('razer') + logger.setLevel(log_level) + formatter = logging.Formatter('%(asctime)s | %(name)-30s | %(levelname)-8s | %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + # Don't propagate to default logger + logger.propagate = 0 + + if want_console_log: + console_logger = logging.StreamHandler() + console_logger.setLevel(log_level) + console_logger.setFormatter(formatter) + logger.addHandler(console_logger) + + if log_dir is not None: + log_file = os.path.join(log_dir, 'razer.log') + file_logger = logging.handlers.RotatingFileHandler(log_file, maxBytes=1048576, backupCount=1) # 1 MiB + file_logger.setLevel(log_level) + file_logger.setFormatter(formatter) + logger.addHandler(file_logger) + + return logger + + def _check_plugdev_group(self): + """ + Check if the user is a member of the plugdev group. For the root + user, this always returns True + + :rtype: bool + """ + if getpass.getuser() == 'root': + return True + + try: + return grp.getgrnam('plugdev').gr_gid in os.getgroups() + except KeyError: + pass + + return False + + def _init_udev_monitor(self): + self._udev_context = Context() + udev_monitor = Monitor.from_netlink(self._udev_context) + udev_monitor.filter_by(subsystem='hid') + self._udev_observer = MonitorObserver(udev_monitor, callback=self._udev_input_event, name='device-monitor') + + def _init_screensaver_monitor(self): + try: + self._screensaver_monitor = ScreensaverMonitor(self) + self._screensaver_monitor.monitoring = self._config.getboolean('Startup', 'devices_off_on_screensaver') + except dbus.exceptions.DBusException as e: + self.logger.error("Failed to init ScreensaverMonitor: {}".format(e)) + + def _init_autosave_persistence(self): + if not self._persistence: + self.logger.debug("Persistence unspecified. Will not create auto save thread") + return + + self._autosave_persistence = PersistenceAutoSave(self._persistence, self._persistence_file, self._persistence.status, self.logger, 10, self.write_persistence) + self._autosave_persistence.thread = threading.Thread(target=self._autosave_persistence.watch) + self._autosave_persistence.thread.daemon = True + self._autosave_persistence.thread.start() + + def _init_signals(self): + """ + Heinous hack to properly handle signals on the mainloop. Necessary + if we want to use the mainloop run() functionality. + """ + def signal_action(signum): + """ + Action to take when a signal is trapped + """ + self.quit(signum) + + def idle_handler(): + """ + GLib idle handler to propagate signals + """ + GLib.idle_add(signal_action, priority=GLib.PRIORITY_HIGH) + + def handler(*args): + """ + Unix signal handler + """ + signal_action(args[0]) + + def install_glib_handler(sig): + """ + Choose a compatible method and install the handler + """ + unix_signal_add = None + + if hasattr(GLib, "unix_signal_add"): + unix_signal_add = GLib.unix_signal_add + elif hasattr(GLib, "unix_signal_add_full"): + unix_signal_add = GLib.unix_signal_add_full + + if unix_signal_add: + unix_signal_add(GLib.PRIORITY_HIGH, sig, handler, sig) + else: + print("Can't install GLib signal handler!") + + for sig in signal.SIGINT, signal.SIGTERM, signal.SIGHUP: + signal.signal(sig, idle_handler) + GLib.idle_add(install_glib_handler, sig, priority=GLib.PRIORITY_HIGH) + + def read_config(self, config_file): + """ + Read in the config file and set the defaults + + :param config_file: Config file + :type config_file: str or None + """ + # Generate sections as trying to access a value even if a default exists will die if the section does not + for section in ('General', 'Startup'): + self._config[section] = {} + + self._config['General'] = { + 'verbose_logging': False, + } + self._config['Startup'] = { + 'sync_effects_enabled': True, + 'devices_off_on_screensaver': True, + 'restore_persistence': True, + 'persistence_dual_boot_quirk': False, + } + + if config_file is not None and os.path.exists(config_file): + self._config.read(config_file) + + # Compatibility to older configs + if 'mouse_battery_notifier' in self._config['Startup']: + self._config['Startup']['battery_notifier'] = self._config['Startup']['mouse_battery_notifier'] + if 'mouse_battery_notifier_freq' in self._config['Startup']: + self._config['Startup']['battery_notifier_freq'] = self._config['Startup']['mouse_battery_notifier_freq'] + + def read_persistence(self, persistence_file): + """ + Read the persistence file and set states into memory + + :param persistence_file: Persistence file + :type persistence_file: str or None + """ + if persistence_file is not None and os.path.exists(persistence_file): + try: + self._persistence.read(persistence_file) + except (configparser.Error, UnicodeDecodeError): + self.logger.warning('Failed to read persistence config, resetting!', exc_info=True) + with open(persistence_file, "w") as f: + f.writelines("") + + def write_persistence(self, persistence_file): + """ + Write in the persistence file + + :param persistence_file: Persistence file + :type persistence_file: str or None + """ + if not persistence_file: + return + + self.logger.debug('Writing persistence config') + + for device in self._razer_devices: + self._persistence[device.dbus.storage_name] = {} + if 'set_dpi_xy' in device.dbus.METHODS or 'set_dpi_xy_byte' in device.dbus.METHODS: + dpi_x = int(device.dbus.dpi[0]) + dpi_y = int(device.dbus.dpi[1]) + # When Y is not greater than 0 check for a DPI X only device, a device with 'available_dpi' and a Y value of 0 + if dpi_x > 0 and (dpi_y > 0 or ('available_dpi' in device.dbus.METHODS and dpi_y == 0)): + self._persistence[device.dbus.storage_name]['dpi_x'] = str(dpi_x) + self._persistence[device.dbus.storage_name]['dpi_y'] = str(dpi_y) + + if 'set_poll_rate' in device.dbus.METHODS: + self._persistence[device.dbus.storage_name]['poll_rate'] = str(device.dbus.poll_rate) + + for i in device.dbus.ZONES: + if device.dbus.zone[i]["present"]: + self._persistence[device.dbus.storage_name][i + '_active'] = str(device.dbus.zone[i]["active"]) + self._persistence[device.dbus.storage_name][i + '_brightness'] = str(device.dbus.zone[i]["brightness"]) + self._persistence[device.dbus.storage_name][i + '_effect'] = device.dbus.zone[i]["effect"] + self._persistence[device.dbus.storage_name][i + '_colors'] = ' '.join(str(i) for i in device.dbus.zone[i]["colors"]) + self._persistence[device.dbus.storage_name][i + '_speed'] = str(device.dbus.zone[i]["speed"]) + self._persistence[device.dbus.storage_name][i + '_wave_dir'] = str(device.dbus.zone[i]["wave_dir"]) + + with open(persistence_file, 'w') as cf: + self._persistence.write(cf) + + def get_off_on_screensaver(self): + """ + Returns if turn off on screensaver + + :return: Result + :rtype: bool + """ + return self._screensaver_monitor.monitoring + + def enable_turn_off_on_screensaver(self, enable): + """ + Enable the turning off of devices when the screensaver is active + """ + self._screensaver_monitor.monitoring = enable + + def supported_devices(self): + result = {cls.__name__: (cls.USB_VID, cls.USB_PID) for cls in self._device_classes} + + return json.dumps(result) + + def version(self): + """ + Get the daemon version + + :return: Version string + :rtype: str + """ + return __version__ + + def suspend_devices(self): + """ + Suspend all devices + """ + for device in self._razer_devices: + device.dbus.suspend_device() + + def resume_devices(self): + """ + Resume all devices + """ + for device in self._razer_devices: + device.dbus.resume_device() + + def get_serial_list(self): + """ + Get list of devices serials + """ + serial_list = self._razer_devices.serials() + self.logger.debug('DBus called get_serial_list') + return serial_list + + def sync_effects(self, enabled): + """ + Sync the effects across the devices + + :param enabled: True to sync effects + :type enabled: bool + """ + # Todo perhaps move logic to device collection + for device in self._razer_devices.devices: + device.dbus.effect_sync = enabled + + def get_sync_effects(self): + """ + Sync the effects across the devices + + :return: True if any devices sync effects + :rtype: bool + """ + result = False + + for device in self._razer_devices.devices: + result |= device.dbus.effect_sync + + return result + + def _load_devices(self, first_run=False): + """ + Go through supported devices and load them + + Loops through the available hardware classes, loops through + each device in the system and adds it if needs be. + """ + if first_run: + # Just some pretty output + max_name_len = max([len(cls.__name__) for cls in self._device_classes]) + 2 + for cls in self._device_classes: + format_str = 'Loaded device specification: {0:-<' + str(max_name_len) + '} ({1:04x}:{2:04X})' + + self.logger.debug(format_str.format(cls.__name__ + ' ', cls.USB_VID, cls.USB_PID)) + + if self._test_dir is not None: + device_list = os.listdir(self._test_dir) + test_mode = True + else: + device_list = list(self._udev_context.list_devices(subsystem='hid')) + test_mode = False + + device_number = 0 + for device in device_list: + + for device_class in self._device_classes: + # Interoperability between generic list of 0000:0000:0000.0000 and pyudev + if test_mode: + sys_name = device + sys_path = os.path.join(self._test_dir, device) + else: + sys_name = device.sys_name + sys_path = device.sys_path + + if sys_name in self._razer_devices: + continue + + if device_class.match(sys_name, sys_path): # Check it matches sys/ ID format and has device_type file + self.logger.info('Found device.%d: %s', device_number, sys_name) + + # TODO add testdir support + # Basically find the other usb interfaces + device_match = sys_name.split('.')[0] + additional_interfaces = [] + if not test_mode: + double_device = False + for alt_device in self._razer_devices: + if device_match in alt_device.device_id and alt_device.device_id != sys_name and sys_path in alt_device.dbus.additional_interfaces: + self.logger.warning('BUG: Device %s has already been found with interface %s. Skipping', sys_name, alt_device.device_id) + double_device = True + if double_device: + continue + + for alt_device in device_list: + if device_match in alt_device.sys_name and alt_device.sys_name != sys_name: + additional_interfaces.append(alt_device.sys_path) + + # Checking permissions + test_file = os.path.join(sys_path, 'device_type') + file_group_id = os.stat(test_file).st_gid + file_group_name = grp.getgrgid(file_group_id)[0] + + if os.getgid() != file_group_id and file_group_name != 'plugdev': + self.logger.critical("Could not access {0}/device_type, file is not owned by plugdev".format(sys_path)) + break + + razer_device = device_class(device_path=sys_path, device_number=device_number, config=self._config, + persistence=self._persistence, testing=self._test_dir is not None, + additional_interfaces=sorted(additional_interfaces), + additional_methods=[], + unknown_serial_counter=self._unknown_serial_counter) + + # Wireless devices sometimes don't listen + count = 0 + while count < 3: + # Loop to get serial, exit early if it gets one + device_serial = razer_device.get_serial() + if len(device_serial) > 0: + break + time.sleep(0.1) + count += 1 + else: + logging.warning("Could not get serial for device {0}. Skipping".format(sys_name)) + continue + + self._razer_devices.add(sys_name, device_serial, razer_device) + + device_number += 1 + + def _add_device(self, device): + """ + Add device event from udev + + :param device: Udev Device + :type device: pyudev.device._device.Device + """ + device_number = len(self._razer_devices) + for device_class in self._device_classes: + sys_name = device.sys_name + sys_path = device.sys_path + + if sys_name in self._razer_devices: + continue + + if device_class.match(sys_name, sys_path): # Check it matches sys/ ID format and has device_type file + self.logger.info('Found valid device.%d: %s', device_number, sys_name) + razer_device = device_class(device_path=sys_path, device_number=device_number, config=self._config, + persistence=self._persistence, testing=self._test_dir is not None, + additional_interfaces=None, additional_methods=[], + unknown_serial_counter=self._unknown_serial_counter) + + # Its a udev event so currently the device hasn't been chmodded yet + time.sleep(0.2) + + # Wireless devices sometimes don't listen + device_serial = razer_device.get_serial() + + if len(device_serial) > 0: + # Add Device + self._razer_devices.add(sys_name, device_serial, razer_device) + self.device_added() + else: + logging.warning("Could not get serial for device {0}. Skipping".format(sys_name)) + else: + # Basically find the other usb interfaces + device_match = sys_name.split('.')[0] + for d in self._razer_devices: + if device_match in d.device_id and d.device_id != sys_name: + if not sys_path in d.dbus.additional_interfaces: + d.dbus.additional_interfaces.append(sys_path) + return + + def _remove_device(self, device): + """ + Remove device event from udev + + :param device: Udev Device + :type device: pyudev.device._device.Device + """ + device_id = device.sys_name + + try: + device = self._razer_devices[device_id] + + device.dbus.close() + device.dbus.remove_from_connection() + self.write_persistence(self._persistence_file) + self.logger.warning("Removing %s", device_id) + + # Delete device + del self._razer_devices[device.device_id] + self.device_removed() + + except IndexError: # Why didn't i set it up as KeyError + # It will return "extra" events for the additional usb interfaces bound to the driver + pass + + def _udev_input_event(self, device): + """ + Function called by the Udev monitor (#observerPattern) + + :param device: Udev device + :type device: pyudev.device._device.Device + """ + self.logger.debug('Device event [%s]: %s', device.action, device.device_path) + if device.action == 'add': + if self._collecting_udev: + self._collecting_udev_devices.append(device) + return + else: + self._collecting_udev_devices = [device] + self._collecting_udev = True + t = threading.Thread(target=self._collecting_udev_method, args=(device,)) + t.start() + elif device.action == 'remove': + self._remove_device(device) + + def _collecting_udev_method(self, device): + time.sleep(2) # delay to let udev add all devices that we want + # Sort the devices + self._collecting_udev_devices.sort(key=lambda x: x.sys_path, reverse=True) + for d in self._collecting_udev_devices: + self._add_device(d) + self._collecting_udev = False + + def run(self): + """ + Run the daemon + """ + self.logger.info('Serving DBus') + + # Start listening for device changes + self._udev_observer.start() + + # Start the mainloop + try: + self._main_loop.run() + except KeyboardInterrupt: + self.logger.debug('Shutting down') + + def stop(self): + """ + Wrapper for quit + """ + self.quit(None) + + def quit(self, signum): + """ + Quit by stopping the main loop, observer, and screensaver thread + """ + # pylint: disable=unused-argument + if signum is None: + self.logger.info('Stopping daemon.') + else: + self.logger.info('Stopping daemon on signal %d', signum) + + self._main_loop.quit() + + # Stop udev monitor + self._udev_observer.send_stop() + + for device in self._razer_devices: + device.dbus.close() + + # Write config + self.write_persistence(self._persistence_file) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/__init__.py b/openrazer/daemon/openrazer_daemon/dbus_services/__init__.py new file mode 100644 index 00000000..9ae89a37 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/__init__.py @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +DBus module + +Has an endpoint decorator to wrap a method for DBus +""" +from functools import wraps + + +def endpoint(interface_name, function_name, in_sig=None, out_sig=None, byte_arrays=False): + """ + DBus Endpoint + + :param interface_name: DBus Interface name + :type interface_name: str + + :param function_name: DBus Method name + :type function_name: str + + :param in_sig: DBus parameter signature + :type in_sig: str + + :param out_sig: DBus return signature + :type out_sig: str + + :param byte_arrays: is Byte Array + :type byte_arrays: bool + + :return: Function + :rtype: callable + """ + # pylint: disable=missing-docstring + def inner_render(func): + def wrapped(*args, **kwargs): + return func(*args, **kwargs) + wrapped.endpoint = True + wrapped.interface = interface_name + wrapped.name = function_name + wrapped.in_sig = in_sig + wrapped.out_sig = out_sig + wrapped.byte_arrays = byte_arrays + wrapped.code = func.__code__ + wrapped.globals = func.__globals__ + wrapped.defaults = func.__defaults__ + wrapped.closure = func.__closure__ + return wraps(func)(wrapped) + return inner_render diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/__init__.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/__init__.py new file mode 100644 index 00000000..557399ac --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/__init__.py @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +All of these effects will be DBus methods +""" + +# pylint: disable=wildcard-import +from openrazer_daemon.dbus_services.dbus_methods.all import * +from openrazer_daemon.dbus_services.dbus_methods.chroma_keyboard import * +from openrazer_daemon.dbus_services.dbus_methods.bw2013 import * +from openrazer_daemon.dbus_services.dbus_methods.mamba import * +from openrazer_daemon.dbus_services.dbus_methods.macro import * +from openrazer_daemon.dbus_services.dbus_methods.keypad import * +from openrazer_daemon.dbus_services.dbus_methods.deathadder_chroma import * +from openrazer_daemon.dbus_services.dbus_methods.nagahexv2 import * +from openrazer_daemon.dbus_services.dbus_methods.nagahex import * +from openrazer_daemon.dbus_services.dbus_methods.lanceheadte import * +from openrazer_daemon.dbus_services.dbus_methods.kraken import * +from openrazer_daemon.dbus_services.dbus_methods.accessory import * +from openrazer_daemon.dbus_services.dbus_methods.charging_pad_chroma import * +from openrazer_daemon.dbus_services.dbus_methods.mouse_scroll_wheel import * +from openrazer_daemon.dbus_services.dbus_methods.argb_controller import * diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/accessory.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/accessory.py new file mode 100644 index 00000000..cacefc9d --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/accessory.py @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Module for accessory methods +""" +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.misc.mug', 'isMugPresent', out_sig='b') +def is_mug_present(self): + """ + Get if the mug is present + + :return: True if there's a mug + :rtype: bool + """ + self.logger.debug("DBus call is_mug_present") + + driver_path = self.get_driver_path('is_mug_present') + + with open(driver_path, 'r') as driver_file: + return int(driver_file.read().strip()) == 1 diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/all.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/all.py new file mode 100644 index 00000000..51ac3e59 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/all.py @@ -0,0 +1,214 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +DBus methods available for all devices. +""" +import os +from openrazer_daemon.dbus_services import endpoint + +# Keyboard layout IDs +# There are more than listed here, but others are not known yet. +layout_ids = { + "01": "en_US", + "02": "el_GR", + "03": "de_DE", + "04": "fr_FR", + "05": "ru_RU", + "06": "en_GB", + "07": "Nordic", + "0a": "tr_TR", + "0c": "ja_JP", + "0f": "de_CH", + "10": "es_ES", + "11": "it_IT", + "12": "pt_PT", + "81": "en_US_mac" +} + + +@endpoint('razer.device.misc', 'getDriverVersion', out_sig='s') +def version(self): + """ + Get the devices driver version + + :return: Get driver version string like 1.0.7 + :rtype: str + """ + self.logger.debug("DBus call version") + + # Caching + if 'driver_version' in self.method_args: + return self.method_args['driver_version'] + + driver_path = self.get_driver_path('version') + + driver_version = '0.0.0' + + if os.path.exists(driver_path): + # Check it exists, as people might not have reloaded driver + with open(driver_path, 'r') as driver_file: + driver_version = driver_file.read().strip() + + self.method_args['driver_version'] = driver_version + return driver_version + + +@endpoint('razer.device.misc', 'getFirmware', out_sig='s') +def get_firmware(self): + """ + Get the devices firmware version + + :return: Get firmware string like v1.1 + :rtype: str + """ + self.logger.debug("DBus call get_firmware") + + driver_path = self.get_driver_path('firmware_version') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() + + +@endpoint('razer.device.misc', 'getDeviceName', out_sig='s') +def get_device_name(self): + """ + Get the device's descriptive string + + :return: Device string like 'BlackWidow Ultimate 2013' + :rtype: str + """ + self.logger.debug("DBus call get_device_name") + + driver_path = self.get_driver_path('device_type') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() + + +@endpoint('razer.device.misc', 'getKeyboardLayout', out_sig='s') +def get_keyboard_layout(self): + """ + Get the device's keyboard layout + + :return: String like 'en_US', 'de_DE', 'en_GB' or 'unknown' + :rtype: str + """ + self.logger.debug("DBus call get_keyboard_layout") + + driver_path = self.get_driver_path('kbd_layout') + + with open(driver_path, 'r') as driver_file: + try: + return layout_ids[driver_file.read().strip()] + except KeyError: + return "unknown" + + +# Functions to define a hardware class +@endpoint('razer.device.misc', 'getDeviceType', out_sig='s') +def get_device_type_keyboard(self): + """ + Get the device's type + + :return: 'keyboard' + :rtype: str + """ + self.logger.debug("DBus call get_device_type") + return 'keyboard' + + +@endpoint('razer.device.misc', 'getDeviceType', out_sig='s') +def get_device_type_mouse(self): + """ + Get the device's type + + :return:'mouse' + :rtype: str + """ + self.logger.debug("DBus call get_device_type") + return 'mouse' + + +@endpoint('razer.device.misc', 'getDeviceType', out_sig='s') +def get_device_type_mousemat(self): + """ + Get the device's type + + :return:'mousemat' + :rtype: str + """ + self.logger.debug("DBus call get_device_type") + return 'mousemat' + + +@endpoint('razer.device.misc', 'getDeviceType', out_sig='s') +def get_device_type_core(self): + """ + Get the device's type + + :return:'core' + :rtype: str + """ + self.logger.debug("DBus call get_device_type") + return 'core' + + +@endpoint('razer.device.misc', 'getDeviceType', out_sig='s') +def get_device_type_keypad(self): + """ + Get the device's type + + :return:'keypad' + :rtype: str + """ + self.logger.debug("DBus call get_device_type") + return 'keypad' + + +@endpoint('razer.device.misc', 'getDeviceType', out_sig='s') +def get_device_type_headset(self): + """ + Get the device's type + + :return:'headset' + :rtype: str + """ + self.logger.debug("DBus call get_device_type") + return 'headset' + + +@endpoint('razer.device.misc', 'getDeviceType', out_sig='s') +def get_device_type_accessory(self): + """ + Get the device's type + + :return:'accessory' + :rtype: str + """ + self.logger.debug("DBus call get_device_type") + return 'accessory' + + +@endpoint('razer.device.misc', 'hasMatrix', out_sig='b') +def has_matrix(self): + """ + If the device has an LED matrix + """ + self.logger.debug("DBus call has_matrix") + + return self.HAS_MATRIX + + +@endpoint('razer.device.misc', 'getMatrixDimensions', out_sig='ai') +def get_matrix_dims(self): + """ + If the device has an LED matrix + """ + self.logger.debug("DBus call has_matrix") + + if not self.HAS_MATRIX: + raise RuntimeError("Device does not have matrix capabilities") + if self.HAS_MATRIX and self.MATRIX_DIMS is None: + raise RuntimeError("HAS_MATRIX is set but no MATRIX_DIMS set!") + + return list(self.MATRIX_DIMS) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/argb_controller.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/argb_controller.py new file mode 100644 index 00000000..d2e55870 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/argb_controller.py @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.channel', 'getNumChannels', out_sig='q') +def get_num_channels(self): + return self.NUM_CHANNELS + + +def _get_channel_brightness(self, channel): + driver_path = self.get_driver_path(channel + '_led_brightness') + with open(driver_path, 'r') as driver_file: + return float(driver_file.read().strip()) / (255.0 / 100.0) + + +@endpoint('razer.device.lighting.channel', 'getChannelBrightness', in_sig='q', out_sig='d') +def get_channel_brightness(self, channel): + """ + Get the channel brightness + + :param channel: Channel number to get the brightness of + :type channel: int + + :return: Brightness + :rtype: float + """ + channel_name = 'channel{}'.format(channel) + self.logger.debug("DBus call get_{}_brightness".format(channel_name)) + return _get_channel_brightness(self, channel_name) + + +def _set_channel_brightness(self, channel, brightness): + driver_path = self.get_driver_path(channel + '_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence(channel, "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.channel', 'setChannelBrightness', in_sig='qd') +def set_channel_brightness(self, channel, brightness): + """ + Set the device's brightness + + :param channel: Channel + :type channel: int + + :param brightness: Brightness + :type brightness: int + """ + channel_name = 'channel{}'.format(channel) + self.logger.debug("DBus call set_{}_brightness".format(channel_name)) + _set_channel_brightness(self, channel_name, brightness) + + +def _get_channel_size(self, channel): + driver_path = self.get_driver_path(channel + '_size') + with open(driver_path, 'r') as driver_file: + return int(driver_file.read().strip()) + + +@endpoint('razer.device.lighting.channel', 'getChannelSize', in_sig='q', out_sig='i') +def get_channel_size(self, channel): + """ + Get the device's size + + :param channel: Channel + :type channel: int + + :return: Size + :rtype: float + """ + channel_name = 'channel{}'.format(channel) + self.logger.debug("DBus call get_{}_size".format(channel_name)) + return _get_channel_size(self, channel_name) + + +def _set_channel_size(self, channel, size): + driver_path = self.get_driver_path(channel + '_size') + + self.method_args['size'] = size + + if size > 255: + size = 255 + elif size < 0: + size = 0 + + self.set_persistence(channel, "size", int(size)) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(size)) + + # Notify others + self.send_effect_event('setSize', size) + + +@endpoint('razer.device.lighting.channel', 'setChannelSize', in_sig='qi') +def set_channel_size(self, channel, size): + """ + Set the device's size + :param channel: Channel + :type channel: int + + :param size: Size + :type size: int + """ + channel_name = 'channel{}'.format(channel) + + self.logger.debug("DBus call set_{}_size".format(channel_name)) + _set_channel_size(self, channel_name, size) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/bw2013.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/bw2013.py new file mode 100644 index 00000000..2daf2ecf --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/bw2013.py @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +BlackWidow Ultimate 2013 effects +""" +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.bw2013', 'setPulsate') +def bw_set_pulsate(self): # TODO: Replace by set*BreathMono + """ + Set pulsate mode + """ + self.logger.debug("DBus call bw_set_pulsate") + + driver_path = self.get_driver_path('matrix_effect_pulsate') + + # remember effect + self.set_persistence("backlight", "effect", 'pulsate') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + # Notify others + self.send_effect_event('setPulsate') + + +@endpoint('razer.device.lighting.bw2013', 'setStatic') +def bw_set_static(self): # TODO: Replace by set*On + """ + Set static mode + """ + self.logger.debug("DBus call bw_set_static") + + driver_path = self.get_driver_path('matrix_effect_static') + + # remember effect + self.set_persistence("backlight", "effect", 'static') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + # Notify others + self.send_effect_event('setStatic') diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/charging_pad_chroma.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/charging_pad_chroma.py new file mode 100644 index 00000000..586d375b --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/charging_pad_chroma.py @@ -0,0 +1,684 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.charging', 'getChargingBrightness', out_sig='d') +def get_charging_brightness(self): + """ + Get the device's brightness + :return: Brightness + :rtype: float + """ + self.logger.debug("DBus call get_charging_brightness") + + return self.zone["charging"]["brightness"] + + +@endpoint('razer.device.lighting.charging', 'setChargingBrightness', in_sig='d') +def set_charging_brightness(self, brightness): + """ + Set the device's brightness + :param brightness: Brightness + :type brightness: int + """ + self.logger.debug("DBus call set_charging_brightness") + + driver_path = self.get_driver_path('charging_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("charging", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.charging', 'setChargingWave', in_sig='i') +def set_charging_wave(self, direction): + """ + Set the wave effect on the device + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_charging_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("charging", "effect", 'wave') + self.set_persistence("charging", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('charging_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.charging', 'setChargingStatic', in_sig='yyy') +def set_charging_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_charging_static") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("charging", "effect", 'static') + self.zone["charging"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('charging_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.charging', 'setChargingSpectrum') +def set_charging_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_charging_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("charging", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('charging_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.charging', 'setChargingNone') +def set_charging_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_charging_none") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("charging", "effect", 'none') + + driver_path = self.get_driver_path('charging_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.charging', 'setChargingBreathRandom') +def set_charging_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_charging_breath_random") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("charging", "effect", 'breathRandom') + + driver_path = self.get_driver_path('charging_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.charging', 'setChargingBreathSingle', in_sig='yyy') +def set_charging_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_charging_breath_single") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("charging", "effect", 'breathSingle') + self.zone["charging"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('charging_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.charging', 'setChargingBreathDual', in_sig='yyyyyy') +def set_charging_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_charging_breath_dual") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("charging", "effect", 'breathDual') + self.zone["charging"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('charging_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.fast_charging', 'getFastChargingBrightness', out_sig='d') +def get_fast_charging_brightness(self): + """ + Get the device's brightness + :return: Brightness + :rtype: float + """ + self.logger.debug("DBus call get_fast_charging_brightness") + + return self.zone["fast_charging"]["brightness"] + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingBrightness', in_sig='d') +def set_fast_charging_brightness(self, brightness): + """ + Set the device's brightness + :param brightness: Brightness + :type brightness: int + """ + self.logger.debug("DBus call set_fast_charging_brightness") + + driver_path = self.get_driver_path('fast_charging_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("fast_charging", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingWave', in_sig='i') +def set_fast_charging_wave(self, direction): + """ + Set the wave effect on the device + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_fast_charging_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("fast_charging", "effect", 'wave') + self.set_persistence("fast_charging", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('fast_charging_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingStatic', in_sig='yyy') +def set_fast_charging_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_fast_charging_static") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("fast_charging", "effect", 'static') + self.zone["fast_charging"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('fast_charging_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingSpectrum') +def set_fast_charging_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_fast_charging_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("fast_charging", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('fast_charging_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingNone') +def set_fast_charging_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_fast_charging_none") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("fast_charging", "effect", 'none') + + driver_path = self.get_driver_path('fast_charging_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingBreathRandom') +def set_fast_charging_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_fast_charging_breath_random") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("fast_charging", "effect", 'breathRandom') + + driver_path = self.get_driver_path('fast_charging_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingBreathSingle', in_sig='yyy') +def set_fast_charging_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_fast_charging_breath_single") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("fast_charging", "effect", 'breathSingle') + self.zone["fast_charging"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('fast_charging_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.fast_charging', 'setFastChargingBreathDual', in_sig='yyyyyy') +def set_fast_charging_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_fast_charging_breath_dual") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("fast_charging", "effect", 'breathDual') + self.zone["fast_charging"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('fast_charging_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.fully_charged', 'getFullyChargedBrightness', out_sig='d') +def get_fully_charged_brightness(self): + """ + Get the device's brightness + :return: Brightness + :rtype: float + """ + self.logger.debug("DBus call get_fully_charged_brightness") + + return self.zone["fully_charged"]["brightness"] + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedBrightness', in_sig='d') +def set_fully_charged_brightness(self, brightness): + """ + Set the device's brightness + :param brightness: Brightness + :type brightness: int + """ + self.logger.debug("DBus call set_fully_charged_brightness") + + driver_path = self.get_driver_path('fully_charged_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("fully_charged", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedWave', in_sig='i') +def set_fully_charged_wave(self, direction): + """ + Set the wave effect on the device + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_fully_charged_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("fully_charged", "effect", 'wave') + self.set_persistence("fully_charged", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('fully_charged_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedStatic', in_sig='yyy') +def set_fully_charged_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_fully_charged_static") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("fully_charged", "effect", 'static') + self.zone["fully_charged"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('fully_charged_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedSpectrum') +def set_fully_charged_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_fully_charged_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("fully_charged", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('fully_charged_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedNone') +def set_fully_charged_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_fully_charged_none") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("fully_charged", "effect", 'none') + + driver_path = self.get_driver_path('fully_charged_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedBreathRandom') +def set_fully_charged_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_fully_charged_breath_random") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("fully_charged", "effect", 'breathRandom') + + driver_path = self.get_driver_path('fully_charged_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedBreathSingle', in_sig='yyy') +def set_fully_charged_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_fully_charged_breath_single") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("fully_charged", "effect", 'breathSingle') + self.zone["fully_charged"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('fully_charged_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.fully_charged', 'setFullyChargedBreathDual', in_sig='yyyyyy') +def set_fully_charged_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_fully_charged_breath_dual") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("fully_charged", "effect", 'breathDual') + self.zone["fully_charged"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('fully_charged_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/chroma_keyboard.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/chroma_keyboard.py new file mode 100644 index 00000000..5fa4e825 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/chroma_keyboard.py @@ -0,0 +1,707 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +BlackWidow Chroma Effects +""" +import os +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.brightness', 'getBrightness', out_sig='d') +def get_brightness(self): + """ + Get the device's brightness + + :return: Brightness + :rtype: float + """ + self.logger.debug("DBus call get_brightness") + + return self.zone["backlight"]["brightness"] + + +@endpoint('razer.device.lighting.brightness', 'setBrightness', in_sig='d') +def set_brightness(self, brightness): + """ + Set the device's brightness + + :param brightness: Brightness + :type brightness: int + """ + self.logger.debug("DBus call set_brightness") + + driver_path = self.get_driver_path('matrix_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("backlight", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.led.gamemode', 'getGameMode', out_sig='b') +def get_game_mode(self): + """ + Get game mode LED state + + :return: Game mode LED state + :rtype: bool + """ + self.logger.debug("DBus call get_game_mode") + + driver_path = self.get_driver_path('game_led_state') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() == '1' + + +@endpoint('razer.device.led.gamemode', 'setGameMode', in_sig='b') +def set_game_mode(self, enable): + """ + Set game mode LED state + + :param enable: Status of game mode + :type enable: bool + """ + self.logger.debug("DBus call set_game_mode") + + driver_path = self.get_driver_path('game_led_state') + + # Checks the usual MOUSE PROTOCOL Interface first + # before checking additional interfaces such as + # the KEYBOARD PROTOCOL. + super_file = self.get_driver_path('key_super') + alt_tab = self.get_driver_path('key_alt_tab') + alt_f4 = self.get_driver_path('key_alt_f4') + + if os.path.exists(super_file): + if enable: + open(super_file, 'wb').write(b'\x01') + open(alt_tab, 'wb').write(b'\x01') + open(alt_f4, 'wb').write(b'\x01') + else: + open(super_file, 'wb').write(b'\x00') + open(alt_tab, 'wb').write(b'\x00') + open(alt_f4, 'wb').write(b'\x00') + else: + for kb_int in self.additional_interfaces: + super_file = os.path.join(kb_int, 'key_super') + alt_tab = os.path.join(kb_int, 'key_alt_tab') + alt_f4 = os.path.join(kb_int, 'key_alt_f4') + + # Some keyboards such as BlackWidow V4 provide additional interfaces + # without key_super, key_alt_tab and key_alt_f4 files. We have to go + # through all interfaces and check if these files are actually available + if os.path.exists(super_file): + if enable: + open(super_file, 'wb').write(b'\x01') + open(alt_tab, 'wb').write(b'\x01') + open(alt_f4, 'wb').write(b'\x01') + else: + open(super_file, 'wb').write(b'\x00') + open(alt_tab, 'wb').write(b'\x00') + open(alt_f4, 'wb').write(b'\x00') + + with open(driver_path, 'w') as driver_file: + if enable: + driver_file.write('1') + else: + driver_file.write('0') + + +@endpoint('razer.device.led.macromode', 'getMacroMode', out_sig='b') +def get_macro_mode(self): + """ + Get macro mode LED state + + :return: Status of macro mode + :rtype: bool + """ + self.logger.debug("DBus call get_macro_mode") + + driver_path = self.get_driver_path('macro_led_state') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() == '1' + + +@endpoint('razer.device.led.macromode', 'setMacroMode', in_sig='b') +def set_macro_mode(self, enable): + """ + Set macro mode LED state + + :param enable: Status of macro mode + :type enable: bool + """ + self.logger.debug("DBus call set_macro_mode") + + driver_path = self.get_driver_path('macro_led_state') + + with open(driver_path, 'w') as driver_file: + if enable: + driver_file.write('1') + else: + driver_file.write('0') + + +@endpoint('razer.device.misc.keyswitchoptimization', 'getKeyswitchOptimization', out_sig='b') +def get_keyswitch_optimization(self): + """ + Get Keyswitch optimization state + + :return: Status of keyswitch optimization + :rtype: bool + """ + self.logger.debug("DBus call get_keyswitch_optimization") + + driver_path = self.get_driver_path('keyswitch_optimization') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() == '1' + + +@endpoint('razer.device.misc.keyswitchoptimization', 'setKeyswitchOptimization', in_sig='b') +def set_keyswitch_optimization(self, enable): + """ + Set Keyswitch optimization state + + :param enable: Status of keyswitch optimization + :type enable: bool + """ + self.logger.debug("DBus call set_keyswitch_optimization") + + driver_path = self.get_driver_path('keyswitch_optimization') + + with open(driver_path, 'w') as driver_file: + if enable: + driver_file.write('1') + else: + driver_file.write('0') + + +@endpoint('razer.device.led.macromode', 'getMacroEffect', out_sig='i') +def get_macro_effect(self): + """ + Get the effect on the macro LED + + :return: Macro LED effect ID + :rtype: int + """ + self.logger.debug("DBus call get_macro_effect") + + driver_path = self.get_driver_path('macro_led_effect') + + with open(driver_path, 'r') as driver_file: + return int(driver_file.read().strip()) + + +@endpoint('razer.device.led.macromode', 'setMacroEffect', in_sig='y') +def set_macro_effect(self, effect): + """ + Set the effect on the macro LED + + :param effect: Macro LED effect ID + :type effect: int + """ + self.logger.debug("DBus call set_macro_effect") + + driver_path = self.get_driver_path('macro_led_effect') + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(int(effect))) + + +@endpoint('razer.device.lighting.chroma', 'setWave', in_sig='i') +def set_wave_effect(self, direction): + """ + Set the wave effect on the device + + :param direction: 1 - left to right, 2 right to left + :type direction: int + """ + self.logger.debug("DBus call set_wave_effect") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("backlight", "effect", 'wave') + self.set_persistence("backlight", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.chroma', 'setWheel', in_sig='i') +def set_wheel_effect(self, direction): + """ + Set the wheel effect on the device + + :param direction: 1 - right, 2 - left + :type direction: int + """ + self.logger.debug("DBus call set_wheel_effect") + + # Notify others + self.send_effect_event('setWheel', direction) + + # Note: wheel direction is saved in wave_dir! + # TODO: Add wheel_dir field handling instead! + self.set_persistence("backlight", "effect", 'wheel') + self.set_persistence("backlight", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('matrix_effect_wheel') + + # If this needs to be configurable, add WHEEL_DIRS like WAVE_DIRS + if direction not in (1, 2): + direction = 1 + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.chroma', 'setStatic', in_sig='yyy') +def set_static_effect(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_static_effect") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("backlight", "effect", 'static') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.chroma', 'setBlinking', in_sig='yyy') +def set_blinking_effect(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_blinking_effect") + + # Notify others + self.send_effect_event('setBlinking', red, green, blue) + + # remember effect + self.set_persistence("backlight", "effect", 'blinking') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('matrix_effect_blinking') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.chroma', 'setSpectrum') +def set_spectrum_effect(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_spectrum_effect") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("backlight", "effect", 'spectrum') + + driver_path = self.get_driver_path('matrix_effect_spectrum') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.chroma', 'setNone') +def set_none_effect(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_none_effect") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("backlight", "effect", 'none') + + driver_path = self.get_driver_path('matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.misc', 'triggerReactive') +def trigger_reactive_effect(self): + """ + Trigger reactive on Firefly + """ + self.logger.debug("DBus call trigger_reactive_effect") + + # Notify others + self.send_effect_event('triggerReactive') + + driver_path = self.get_driver_path('matrix_reactive_trigger') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.chroma', 'setReactive', in_sig='yyyy') +def set_reactive_effect(self, red, green, blue, speed): + """ + Set the device to reactive effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + + :param speed: Speed + :type speed: int + """ + self.logger.debug("DBus call set_reactive_effect") + + driver_path = self.get_driver_path('matrix_effect_reactive') + + # Notify others + self.send_effect_event('setReactive', red, green, blue, speed) + + # remember effect + self.set_persistence("backlight", "effect", 'reactive') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + if speed not in (1, 2, 3, 4): + speed = 4 + + self.set_persistence("backlight", "speed", int(speed)) + + payload = bytes([speed, red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.chroma', 'setBreathRandom') +def set_breath_random_effect(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_breath_random_effect") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("backlight", "effect", 'breathRandom') + + driver_path = self.get_driver_path('matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.chroma', 'setBreathSingle', in_sig='yyy') +def set_breath_single_effect(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_breath_single_effect") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("backlight", "effect", 'breathSingle') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.chroma', 'setBreathDual', in_sig='yyyyyy') +def set_breath_dual_effect(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_breath_dual_effect") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("backlight", "effect", 'breathDual') + self.zone["backlight"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.chroma', 'setBreathTriple', in_sig='yyyyyyyyy') +def set_breath_triple_effect(self, red1, green1, blue1, red2, green2, blue2, red3, green3, blue3): + """ + Set the device to triple colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + + :param red3: Red component + :type red3: int + + :param green3: Green component + :type green3: int + + :param blue3: Blue component + :type blue3: int + """ + self.logger.debug("DBus call set_breath_triple_effect") + + # Notify others + self.send_effect_event('setBreathTriple', red1, green1, blue1, red2, green2, blue2, red3, green3, blue3) + + # remember effect + self.set_persistence("backlight", "effect", 'breathTriple') + self.zone["backlight"]["colors"][0:9] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2), int(red3), int(green3), int(blue3) + + driver_path = self.get_driver_path('matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2, red3, green3, blue3]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.chroma', 'setCustom') +def set_custom_effect(self): + """ + Set the device to use custom LED matrix + """ + self.send_effect_event('setCustom') + + self._set_custom_effect() + + +@endpoint('razer.device.lighting.chroma', 'setKeyRow', in_sig='ay', byte_arrays=True) +def set_key_row(self, payload): + """ + Set the RGB matrix on the device + + Byte array like + [1, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, + 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 00, 00] + + First byte is row, on firefly its always 1, on keyboard its 0-5 + Then its 3byte groups of RGB + :param payload: Binary payload + :type payload: bytes + """ + self.send_effect_event('setCustom') + + self._set_key_row(payload) + + +@endpoint('razer.device.lighting.custom', 'setRipple', in_sig='yyyd') +def set_ripple_effect(self, red, green, blue, refresh_rate): + """ + Set the daemon to serve a ripple effect of the specified colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + + :param refresh_rate: Refresh rate + :type refresh_rate: int + """ + self.logger.debug("DBus call set_ripple_effect") + + # Notify others + self.send_effect_event('setRipple', red, green, blue, refresh_rate) + + # remember effect + self.set_persistence("backlight", "effect", 'ripple') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + +@endpoint('razer.device.lighting.custom', 'setRippleRandomColour', in_sig='d') +def set_ripple_effect_random_colour(self, refresh_rate): + """ + Set the daemon to serve a ripple effect of random colours + + :param refresh_rate: Refresh rate + :type refresh_rate: int + """ + self.logger.debug("DBus call set_ripple_effect") + + # Notify others + self.send_effect_event('setRipple', None, None, None, refresh_rate) + + # remember effect + self.set_persistence("backlight", "effect", 'rippleRandomColour') + + +@endpoint('razer.device.lighting.chroma', 'setStarlightRandom', in_sig='y') +def set_starlight_random_effect(self, speed): + """ + Set startlight random mode + """ + self.logger.debug("DBus call set_starlight_random") + + driver_path = self.get_driver_path('matrix_effect_starlight') + + with open(driver_path, 'wb') as driver_file: + driver_file.write(bytes([speed])) + + # Notify others + self.send_effect_event('setStarlightRandom') + + # remember effect + self.set_persistence("backlight", "effect", 'starlightRandom') + self.set_persistence("backlight", "speed", int(speed)) + + +@endpoint('razer.device.lighting.chroma', 'setStarlightSingle', in_sig='yyyy') +def set_starlight_single_effect(self, red, green, blue, speed): + """ + Set starlight mode + """ + self.logger.debug("DBus call set_starlight_single") + + driver_path = self.get_driver_path('matrix_effect_starlight') + + with open(driver_path, 'wb') as driver_file: + driver_file.write(bytes([speed, red, green, blue])) + + # Notify others + self.send_effect_event('setStarlightSingle', red, green, blue, speed) + + # remember effect + self.set_persistence("backlight", "effect", 'starlightSingle') + self.set_persistence("backlight", "speed", int(speed)) + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + +@endpoint('razer.device.lighting.chroma', 'setStarlightDual', in_sig='yyyyyyy') +def set_starlight_dual_effect(self, red1, green1, blue1, red2, green2, blue2, speed): + """ + Set starlight dual mode + """ + self.logger.debug("DBus call set_starlight_dual") + + driver_path = self.get_driver_path('matrix_effect_starlight') + + with open(driver_path, 'wb') as driver_file: + driver_file.write(bytes([speed, red1, green1, blue1, red2, green2, blue2])) + + # Notify others + self.send_effect_event('setStarlightDual', red1, green1, blue1, red2, green2, blue2, speed) + + # remember effect + self.set_persistence("backlight", "effect", 'starlightDual') + self.set_persistence("backlight", "speed", int(speed)) + self.zone["backlight"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/deathadder_chroma.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/deathadder_chroma.py new file mode 100644 index 00000000..cfd7cbcf --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/deathadder_chroma.py @@ -0,0 +1,140 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.backlight', 'getBacklightBrightness', out_sig='d') +def get_backlight_brightness(self): + """ + Get the device's brightness + """ + self.logger.debug("DBus call get_backlight_brightness") + + return self.zone["backlight"]["brightness"] + + +@endpoint('razer.device.lighting.backlight', 'setBacklightBrightness', in_sig='d') +def set_backlight_brightness(self, brightness): + """ + Set the device's brightness + """ + self.logger.debug("DBus call set_backlight_brightness") + + driver_path = self.get_driver_path('backlight_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("backlight", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.logo', 'getLogoActive', out_sig='b') +def get_logo_active(self): + """ + Get if the logo is lit up + """ + self.logger.debug("DBus call get_logo_active") + + return self.zone["logo"]["active"] + + +@endpoint('razer.device.lighting.logo', 'setLogoActive', in_sig='b') +def set_logo_active(self, active): + """ + Set if the logo is lit up + """ + self.logger.debug("DBus call set_logo_active") + + # remember status + self.set_persistence("logo", "active", bool(active)) + + driver_path = self.get_driver_path('logo_led_state') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1' if active else '0') + + +@endpoint('razer.device.lighting.logo', 'getLogoBrightness', out_sig='d') +def get_logo_brightness(self): + """ + Get the device's brightness + """ + self.logger.debug("DBus call get_logo_brightness") + + return self.zone["logo"]["brightness"] + + +@endpoint('razer.device.lighting.logo', 'setLogoBrightness', in_sig='d') +def set_logo_brightness(self, brightness): + """ + Set the device's brightness + """ + self.logger.debug("DBus call set_logo_brightness") + + driver_path = self.get_driver_path('logo_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("logo", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.scroll', 'getScrollBrightness', out_sig='d') +def get_scroll_brightness(self): + """ + Get the device's brightness + """ + self.logger.debug("DBus call get_scroll_brightness") + + return self.zone["scroll"]["brightness"] + + +@endpoint('razer.device.lighting.scroll', 'setScrollBrightness', in_sig='d') +def set_scroll_brightness(self, brightness): + """ + Set the device's brightness + """ + self.logger.debug("DBus call set_scroll_brightness") + + driver_path = self.get_driver_path('scroll_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("scroll", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/keypad.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/keypad.py new file mode 100644 index 00000000..927a405c --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/keypad.py @@ -0,0 +1,137 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Keypad Effects +""" +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.profile_led', 'getRedLED', out_sig='b') +def keypad_get_profile_led_red(self): + """ + Get red profile LED state + + :return: Red profile LED state + :rtype: bool + """ + self.logger.debug("DBus call keypad_profile_led_red") + + driver_path = self.get_driver_path('profile_led_red') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() == '1' + + +@endpoint('razer.device.lighting.profile_led', 'setRedLED', in_sig='b') +def keypad_set_profile_led_red(self, enable): + """ + Set red profile LED state + + :param enable: Status of red profile LED + :type enable: bool + """ + self.logger.debug("DBus call keypad_set_profile_led_red") + + driver_path = self.get_driver_path('profile_led_red') + + with open(driver_path, 'w') as driver_file: + if enable: + driver_file.write('1') + else: + driver_file.write('0') + + +@endpoint('razer.device.lighting.profile_led', 'getGreenLED', out_sig='b') +def keypad_get_profile_led_green(self): + """ + Get green profile LED state + + :return: Green profile LED state + :rtype: bool + """ + self.logger.debug("DBus call keypad_get_profile_led_green") + + driver_path = self.get_driver_path('profile_led_green') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() == '1' + + +@endpoint('razer.device.lighting.profile_led', 'setGreenLED', in_sig='b') +def keypad_set_profile_led_green(self, enable): + """ + Set green profile LED state + + :param enable: Status of green profile LED + :type enable: bool + """ + self.logger.debug("DBus call keypad_set_profile_led_green") + + driver_path = self.get_driver_path('profile_led_green') + + with open(driver_path, 'w') as driver_file: + if enable: + driver_file.write('1') + else: + driver_file.write('0') + + +@endpoint('razer.device.lighting.profile_led', 'getBlueLED', out_sig='b') +def keypad_get_profile_led_blue(self): + """ + Get blue profile LED state + + :return: Blue profile LED state + :rtype: bool + """ + self.logger.debug("DBus call keypad_get_profile_led_blue") + + driver_path = self.get_driver_path('profile_led_blue') + + with open(driver_path, 'r') as driver_file: + return driver_file.read().strip() == '1' + + +@endpoint('razer.device.lighting.profile_led', 'setBlueLED', in_sig='b') +def keypad_set_profile_led_blue(self, enable): + """ + Set blue profile LED state + + :param enable: Status of blue profile LED + :type enable: bool + """ + self.logger.debug("DBus call keypad_set_profile_led_blue") + + driver_path = self.get_driver_path('profile_led_blue') + + with open(driver_path, 'w') as driver_file: + if enable: + driver_file.write('1') + else: + driver_file.write('0') + + +@endpoint('razer.device.macro', 'getModeModifier', out_sig='b') +def keypad_get_mode_modifier(self): + """ + Get if the mode key is a modifier + + :return: State + :rtype: bool + """ + self.logger.debug("DBus call keypad_get_mode_modifier") + + return self.key_manager.mode_modifier + + +@endpoint('razer.device.macro', 'setModeModifier', in_sig='b') +def keypad_set_mode_modifier(self, modifier): + """ + Set if the mode key is a modifier + + :param modifier: State + :type modifier: bool + """ + self.logger.debug("DBus call keypad_set_mode_modifier") + + self.key_manager.mode_modifier = modifier diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/kraken.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/kraken.py new file mode 100644 index 00000000..96b391a0 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/kraken.py @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Module for kraken methods +""" +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.kraken', 'setCustom', in_sig='ai') +def set_custom_kraken(self, rgbi): + """ + Set custom colour on kraken + + :return: List of args used for breathing effect + :rtype: int + """ + self.logger.debug("DBus call set custom") + + driver_path = self.get_driver_path('matrix_effect_custom') + + if len(rgbi) not in (3, 4): + raise ValueError("List must be of 3 or 4 bytes") + + # DodgyCoding + rgbi_list = list(rgbi) + for index, item in enumerate(list(rgbi)): + item = int(item) + + if item < 0: + rgbi_list[index] = 0 + elif item > 255: + rgbi_list[index] = 255 + else: + rgbi_list[index] = item + + with open(driver_path, 'wb') as driver_file: + driver_file.write(bytes(rgbi_list)) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/lanceheadte.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/lanceheadte.py new file mode 100644 index 00000000..504bf0f2 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/lanceheadte.py @@ -0,0 +1,837 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.logo', 'setLogoWave', in_sig='i') +def set_logo_wave(self, direction): + """ + Set the wave effect on the device + + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_logo_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("logo", "effect", 'wave') + self.set_persistence("logo", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('logo_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.scroll', 'setScrollWave', in_sig='i') +def set_scroll_wave(self, direction): + """ + Set the wave effect on the device + + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_scroll_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("scroll", "effect", 'wave') + self.set_persistence("scroll", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('scroll_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.left', 'getLeftBrightness', out_sig='d') +def get_left_brightness(self): + """ + Get the device's brightness + + :return: Brightness + :rtype: float + """ + self.logger.debug("DBus call get_left_brightness") + + return self.zone["left"]["brightness"] + + +@endpoint('razer.device.lighting.left', 'setLeftBrightness', in_sig='d') +def set_left_brightness(self, brightness): + """ + Set the device's brightness + + :param brightness: Brightness + :type brightness: int + """ + self.logger.debug("DBus call set_left_brightness") + + driver_path = self.get_driver_path('left_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("left", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.left', 'setLeftWave', in_sig='i') +def set_left_wave(self, direction): + """ + Set the wave effect on the device + + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_left_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("left", "effect", 'wave') + self.set_persistence("left", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('left_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.left', 'setLeftStatic', in_sig='yyy') +def set_left_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_left_static") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("left", "effect", 'static') + self.zone["left"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('left_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.left', 'setLeftSpectrum') +def set_left_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_left_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("left", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('left_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.left', 'setLeftNone') +def set_left_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_left_none") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("left", "effect", 'none') + + driver_path = self.get_driver_path('left_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.left', 'setLeftReactive', in_sig='yyyy') +def set_left_reactive(self, red, green, blue, speed): + """ + Set the device to reactive effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + + :param speed: Speed + :type speed: int + """ + self.logger.debug("DBus call set_left_reactive") + + driver_path = self.get_driver_path('left_matrix_effect_reactive') + + # Notify others + self.send_effect_event('setReactive', red, green, blue, speed) + + # remember effect + self.set_persistence("left", "effect", 'reactive') + self.zone["left"]["colors"][0:3] = int(red), int(green), int(blue) + + if speed not in (1, 2, 3, 4): + speed = 4 + + self.set_persistence("left", "speed", int(speed)) + + payload = bytes([speed, red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.left', 'setLeftBreathRandom') +def set_left_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_left_breath_random") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("left", "effect", 'breathRandom') + + driver_path = self.get_driver_path('left_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.left', 'setLeftBreathSingle', in_sig='yyy') +def set_left_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_left_breath_single") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("left", "effect", 'breathSingle') + self.zone["left"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('left_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.left', 'setLeftBreathDual', in_sig='yyyyyy') +def set_left_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_left_breath_dual") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("left", "effect", 'breathDual') + self.zone["left"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('left_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.right', 'getRightBrightness', out_sig='d') +def get_right_brightness(self): + """ + Get the device's brightness + :return: Brightness + :rtype: float + """ + self.logger.debug("DBus call get_right_brightness") + + return self.zone["right"]["brightness"] + + +@endpoint('razer.device.lighting.right', 'setRightBrightness', in_sig='d') +def set_right_brightness(self, brightness): + """ + Set the device's brightness + + :param brightness: Brightness + :type brightness: int + """ + self.logger.debug("DBus call set_right_brightness") + + driver_path = self.get_driver_path('right_led_brightness') + + self.method_args['brightness'] = brightness + + if brightness > 100: + brightness = 100 + elif brightness < 0: + brightness = 0 + + self.set_persistence("right", "brightness", int(brightness)) + + brightness = int(round(brightness * (255.0 / 100.0))) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(brightness)) + + # Notify others + self.send_effect_event('setBrightness', brightness) + + +@endpoint('razer.device.lighting.right', 'setRightWave', in_sig='i') +def set_right_wave(self, direction): + """ + Set the wave effect on the device + + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_right_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("right", "effect", 'wave') + self.set_persistence("right", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('right_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.right', 'setRightStatic', in_sig='yyy') +def set_right_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_right_static") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("right", "effect", 'static') + self.zone["right"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('right_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.right', 'setRightSpectrum') +def set_right_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_right_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("right", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('right_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.right', 'setRightNone') +def set_right_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_right_none") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("right", "effect", 'none') + + driver_path = self.get_driver_path('right_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.right', 'setRightReactive', in_sig='yyyy') +def set_right_reactive(self, red, green, blue, speed): + """ + Set the device to reactive effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + + :param speed: Speed + :type speed: int + """ + self.logger.debug("DBus call set_right_reactive") + + driver_path = self.get_driver_path('right_matrix_effect_reactive') + + # Notify others + self.send_effect_event('setReactive', red, green, blue, speed) + + # remember effect + self.set_persistence("right", "effect", 'reactive') + self.zone["right"]["colors"][0:3] = int(red), int(green), int(blue) + + if speed not in (1, 2, 3, 4): + speed = 4 + + self.set_persistence("right", "speed", int(speed)) + + payload = bytes([speed, red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.right', 'setRightBreathRandom') +def set_right_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_right_breath_random") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("right", "effect", 'breathRandom') + + driver_path = self.get_driver_path('right_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.right', 'setRightBreathSingle', in_sig='yyy') +def set_right_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_right_breath_single") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("right", "effect", 'breathSingle') + self.zone["right"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('right_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.right', 'setRightBreathDual', in_sig='yyyyyy') +def set_right_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_right_breath_dual") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("right", "effect", 'breathDual') + self.zone["right"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('right_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.backlight', 'setBacklightWave', in_sig='i') +def set_backlight_wave(self, direction): + """ + Set the wave effect on the device + + :param direction: (0|1) - down to up, (1|2) up to down + :type direction: int + """ + self.logger.debug("DBus call set_backlight_wave") + + # Notify others + self.send_effect_event('setWave', direction) + + # remember effect + self.set_persistence("backlight", "effect", 'wave') + self.set_persistence("backlight", "wave_dir", int(direction)) + + driver_path = self.get_driver_path('backlight_matrix_effect_wave') + + if direction not in self.WAVE_DIRS: + direction = self.WAVE_DIRS[0] + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(direction)) + + +@endpoint('razer.device.lighting.backlight', 'setBacklightStatic', in_sig='yyy') +def set_backlight_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_backlight_static") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("backlight", "effect", 'static') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('backlight_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.backlight', 'setBacklightSpectrum') +def set_backlight_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_backlight_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("backlight", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('backlight_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.backlight', 'setBacklightNone') +def set_backlight_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_backlight_none") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("backlight", "effect", 'none') + + driver_path = self.get_driver_path('backlight_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.backlight', 'setBacklightOn') +def set_backlight_on(self): + """ + Set the device to effect on + """ + self.logger.debug("DBus call set_backlight_on") + + # Notify others + self.send_effect_event('setOn') + + # remember effect + self.set_persistence("backlight", "effect", 'on') + + driver_path = self.get_driver_path('backlight_matrix_effect_on') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.backlight', 'setBacklightReactive', in_sig='yyyy') +def set_backlight_reactive(self, red, green, blue, speed): + """ + Set the device to reactive effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + + :param speed: Speed + :type speed: int + """ + self.logger.debug("DBus call set_backlight_reactive") + + driver_path = self.get_driver_path('backlight_matrix_effect_reactive') + + # Notify others + self.send_effect_event('setReactive', red, green, blue, speed) + + # remember effect + self.set_persistence("backlight", "effect", 'reactive') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + if speed not in (1, 2, 3, 4): + speed = 4 + + self.set_persistence("backlight", "speed", int(speed)) + + payload = bytes([speed, red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.backlight', 'setBacklightBreathRandom') +def set_backlight_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_backlight_breath_random") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("backlight", "effect", 'breathRandom') + + driver_path = self.get_driver_path('backlight_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.backlight', 'setBacklightBreathSingle', in_sig='yyy') +def set_backlight_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_backlight_breath_single") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("backlight", "effect", 'breathSingle') + self.zone["backlight"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('backlight_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.backlight', 'setBacklightBreathDual', in_sig='yyyyyy') +def set_backlight_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_backlight_breath_dual") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("backlight", "effect", 'breathDual') + self.zone["backlight"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('backlight_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/macro.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/macro.py new file mode 100644 index 00000000..f5f1f062 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/macro.py @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +BlackWidow Macro accessors +""" +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.macro', 'getMacros', out_sig='s') +def get_macros(self): + """ + Get macros + + :return: JSON of macros + :rtype: str + """ + self.logger.debug("DBus call get_macros") + + return self.key_manager.dbus_get_macros() + + +@endpoint('razer.device.macro', 'deleteMacro', in_sig='s') +def delete_macro(self, macro_key): + """ + Delete macro from key + + :param macro_key: Macro key to delete bound macro from + :type macro_key: str + """ + self.logger.debug("DBus call delete_macro") + + self.key_manager.dbus_delete_macro(macro_key) + + +@endpoint('razer.device.macro', 'addMacro', in_sig='ss') +def add_macro(self, macro_bind_key, macro_json): + """ + Add macro to key + + The macro_json should be JSON form of a list of dictionaries + :param macro_bind_key: Macro key to delete bound macro from + :type macro_bind_key: str + + :param macro_json: JSON list + :type macro_json: str + """ + self.logger.debug("DBus call add_macro") + + self.key_manager.dbus_add_macro(macro_bind_key, macro_json) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/mamba.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/mamba.py new file mode 100644 index 00000000..48a9e758 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/mamba.py @@ -0,0 +1,397 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import math +import struct +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.power', 'getBattery', out_sig='d') +def get_battery(self): + """ + Get mouse's battery level + """ + self.logger.debug("DBus call get_battery") + + driver_path = self.get_driver_path('charge_level') + + with open(driver_path, 'r') as driver_file: + battery_255 = float(driver_file.read().strip()) + if battery_255 < 0: + return -1.0 + + battery_100 = (battery_255 / 255) * 100 + return battery_100 + + +@endpoint('razer.device.power', 'isCharging', out_sig='b') +def is_charging(self): + """ + Get charging status + """ + self.logger.debug("DBus call is_charging") + + driver_path = self.get_driver_path('charge_status') + + with open(driver_path, 'r') as driver_file: + return bool(int(driver_file.read().strip())) + + +@endpoint('razer.device.power', 'setIdleTime', in_sig='q') +def set_idle_time(self, idle_time): + """ + Set the idle time of the mouse in seconds + + :param idle_time: Idle time in seconds (unsigned short) + :type idle_time: int + """ + self.logger.debug("DBus call set_idle_time") + + driver_path = self.get_driver_path('device_idle_time') + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(idle_time)) + + +@endpoint('razer.device.power', 'getIdleTime', out_sig='q') +def get_idle_time(self): + """ + Get the idle time of the mouse in seconds + + :return: Idle time in seconds (unsigned short) + :rtype: int + """ + self.logger.debug("DBus call get_idle_time") + + driver_path = self.get_driver_path('device_idle_time') + + with open(driver_path, 'r') as driver_file: + result = driver_file.read() + result = int(result.strip()) + + return result + + +@endpoint('razer.device.power', 'setLowBatteryThreshold', in_sig='y') +def set_low_battery_threshold(self, threshold): + """ + Set the low battery threshold as a percentage + + :param threshold: Battery threshold as a percentage + :type threshold: int + """ + self.logger.debug("DBus call set_low_battery_threshold") + + driver_path = self.get_driver_path('charge_low_threshold') + + threshold = math.floor((threshold / 100) * 255) + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(threshold)) + + +@endpoint('razer.device.power', 'getLowBatteryThreshold', out_sig='y') +def get_low_battery_threshold(self): + """ + Get the low battery threshold as a percentage + + :return: Battery threshold as a percentage + :rtype: int + """ + self.logger.debug("DBus call get_low_battery_threshold") + + driver_path = self.get_driver_path('charge_low_threshold') + + with open(driver_path, 'r') as driver_file: + result = driver_file.read() + result = int(result.strip()) + + return round((result / 255) * 100) + + +@endpoint('razer.device.lighting.power', 'setChargeEffect', in_sig='y') +def set_charge_effect(self, charge_effect): + """ + Set the charging effect. + + If 0x00 then it will use the current mouse's effect + If 0x01 it will use the charge colour + + :param charge_effect: Charge effect + :type charge_effect: int + :return: + """ + self.logger.debug("DBus call set_charge_effect") + + driver_path = self.get_driver_path('charge_effect') + + with open(driver_path, 'wb') as driver_file: + driver_file.write(bytes([charge_effect])) + + +@endpoint('razer.device.lighting.power', 'setChargeColour', in_sig='yyy') +def set_charge_colour(self, red, green, blue): + """ + Set the charge colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_charge_colour") + + driver_path = self.get_driver_path('charge_colour') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.dpi', 'setDPI', in_sig='qq') +def set_dpi_xy(self, dpi_x, dpi_y): + """ + Set the DPI on the mouse, Takes in 4 bytes big-endian + + :param dpi_x: X DPI + :type dpi_x: int + :param dpi_y: Y DPI + :type dpi_x: int + """ + self.logger.debug("DBus call set_dpi_xy") + + if 'available_dpi' in self.METHODS: + if dpi_y > 0: + raise RuntimeError("Devices with available_dpi are expected to have only one DPI value set, got " + str(dpi_x) + ", " + str(dpi_y)) + if dpi_x not in self.AVAILABLE_DPI: + raise RuntimeError("Provided DPI " + str(dpi_x) + " is not in available_dpi values: " + str(self.AVAILABLE_DPI)) + + # check that DPI is not more than the maximum + if dpi_x > self.DPI_MAX: + raise RuntimeError("Provided DPI " + str(dpi_x) + " is larger than maximum of " + str(self.DPI_MAX)) + if dpi_y > self.DPI_MAX: + raise RuntimeError("Provided DPI " + str(dpi_x) + " is larger than maximum of " + str(self.DPI_MAX)) + + driver_path = self.get_driver_path('dpi') + + if self._testing: + with open(driver_path, 'w') as driver_file: + if dpi_y <= 0: + driver_file.write("{}".format(dpi_x)) + else: + driver_file.write("{}:{}".format(dpi_x, dpi_y)) + return + + # If the application requests just one value to be written + if dpi_y <= 0: + dpi_bytes = struct.pack('>H', dpi_x) + else: + dpi_bytes = struct.pack('>HH', dpi_x, dpi_y) + + # store to local variable (TODO: can we replace this by getting from persistence?) + self.dpi[0] = dpi_x + self.dpi[1] = dpi_y + + self.set_persistence(None, "dpi_x", dpi_x) + self.set_persistence(None, "dpi_y", dpi_y) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(dpi_bytes) + + +@endpoint('razer.device.dpi', 'getDPI', out_sig='ai') +def get_dpi_xy(self): + """ + get the DPI on the mouse + + :return: List of X, Y DPI + :rtype: list of int + """ + self.logger.debug("DBus call get_dpi_xy") + + driver_path = self.get_driver_path('dpi') + + # try retrieving DPI from the hardware. + # if we can't (e.g. because the mouse has been disconnected) + # return the value in local storage. + try: + with open(driver_path, 'r') as driver_file: + result = driver_file.read() + dpi = [int(dpi) for dpi in result.strip().split(':')] + except FileNotFoundError: + return self.dpi + + if 'available_dpi' in self.METHODS: + if len(dpi) != 1: + raise RuntimeError("Devices with available_dpi are expected to have only one DPI value returned from driver, got " + str(dpi)) + dpi = dpi[0], 0 + + return dpi + + +@endpoint('razer.device.dpi', 'setDPIStages', in_sig='ya(qq)') +def set_dpi_stages(self, active_stage, dpi_stages): + """ + Set the DPI on the mouse, Takes in pairs of 2 bytes big-endian + + :param active_stage: DPI stage to enable + :param dpi_stages: pairs of dpi X and dpi Y for each stage + :type dpi_stages: list of (int, int) + """ + self.logger.debug("DBus call set_dpi_stages") + + driver_path = self.get_driver_path('dpi_stages') + + dpi_bytes = struct.pack('B', active_stage) + for dpi_x, dpi_y in dpi_stages: + dpi_bytes += struct.pack('>HH', dpi_x, dpi_y) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(dpi_bytes) + + +@endpoint('razer.device.dpi', 'getDPIStages', out_sig='(ya(qq))') +def get_dpi_stages(self): + """ + get the DPI stages on the mouse + + :return: List of X, Y DPI + :rtype: (int, list of (int, int)) + """ + self.logger.debug("DBus call get_dpi_stages") + + driver_path = self.get_driver_path('dpi_stages') + + dpi_stages = [] + with open(driver_path, 'rb') as driver_file: + result = driver_file.read() + + (active_stage,) = struct.unpack('B', result[:1]) + result = result[1:] + + while len(result) >= 4: + (dpi_x, dpi_y) = struct.unpack('>HH', result[:4]) + dpi_stages.append((dpi_x, dpi_y)) + result = result[4:] + + return (active_stage, dpi_stages) + + +@endpoint('razer.device.dpi', 'maxDPI', out_sig='i') +def max_dpi(self): + self.logger.debug("DBus call max_dpi") + + return self.DPI_MAX + + +@endpoint('razer.device.dpi', 'availableDPI', out_sig='ai') +def available_dpi(self): + self.logger.debug("DBus call available_dpi") + + if hasattr(self, 'AVAILABLE_DPI'): + return self.AVAILABLE_DPI + + return [] + + +@endpoint('razer.device.misc', 'setPollRate', in_sig='q') +def set_poll_rate(self, rate): + """ + Set the polling rate on the device, Takes in 4 bytes big-endian + + :param rate: Poll rate + :type rate: int + """ + self.logger.debug("DBus call set_poll_rate") + + if rate not in self.POLL_RATES: + raise RuntimeError("Poll rate " + str(rate) + " is not allowed. Allowed values: " + str(self.POLL_RATES)) + + driver_path = self.get_driver_path('poll_rate') + + # remember poll rate + self.poll_rate = rate + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(rate)) + + +@endpoint('razer.device.misc', 'getPollRate', out_sig='i') +def get_poll_rate(self): + """ + Get the polling rate from the device + + :return: Poll rate + :rtype: int + """ + self.logger.debug("DBus call get_poll_rate") + + return int(self.poll_rate) + + +@endpoint('razer.device.misc', 'getSupportedPollRates', out_sig='aq') +def get_supported_poll_rates(self): + """ + Get the polling rates supported by the device + + :return: Supported poll rates + :rtype: list of int + """ + self.logger.debug("DBus call get_supported_poll_rates") + + return self.POLL_RATES + + +@endpoint('razer.device.misc', 'setHyperPollingLED', in_sig='y') +def set_hyperpolling_wireless_dongle_indicator_led_mode(self, mode): + """ + Set the function of the LED on the dongle, takes in 1 char + 1 = Connection Status (green if connected to mouse) + 2 = Battery Status (green if high battery, yellow if medium battery, red if low battery) + 3 = Battery Warning (red if low battery, off otherwise) + + :param mode: LED mode + :type mode: char + """ + self.logger.debug("DBus call set_hyperpolling_wireless_dongle_indicator_led_mode") + + driver_path = self.get_driver_path('hyperpolling_wireless_dongle_indicator_led_mode') + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(mode)) + + +@endpoint('razer.device.misc', 'setHyperPollingPair', in_sig='s') +def set_hyperpolling_wireless_dongle_pair(self, pid): + """ + Set Pairing mode, takes in 1 string which is the PID + + :param pid: product id + :type pid: char + """ + self.logger.debug("DBus call set_hyperpolling_wireless_dongle_pair") + + driver_path = self.get_driver_path('hyperpolling_wireless_dongle_pair') + + with open(driver_path, 'w') as driver_file: + driver_file.write(pid) + + +@endpoint('razer.device.misc', 'setHyperPollingUnpair', in_sig='s') +def set_hyperpolling_wireless_dongle_unpair(self, pid): + """ + Set Unpairing mode, takes in 1 string which is the PID + + :param pid: product id + :type pid: char + """ + self.logger.debug("DBus call set_hyperpolling_wireless_dongle_unpair") + + driver_path = self.get_driver_path('hyperpolling_wireless_dongle_unpair') + + with open(driver_path, 'w') as driver_file: + driver_file.write(pid) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/mouse_scroll_wheel.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/mouse_scroll_wheel.py new file mode 100644 index 00000000..7042f8b3 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/mouse_scroll_wheel.py @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.scroll', 'setScrollMode', in_sig='y') +def set_scroll_mode(self, mode): + """ + Set the device's scroll mode + + :param mode: The mode to set (0 = tactile, 1 = free spin) + :type mode: int + """ + self.logger.debug("DBus call set_scroll_mode") + + if mode not in (0, 1): + raise ValueError("mode has to be 0 or 1") + + driver_path = self.get_driver_path('scroll_mode') + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(int(mode))) + + +@endpoint('razer.device.scroll', 'getScrollMode', out_sig='y') +def get_scroll_mode(self): + """ + Get the device's current scroll mode + + :return: The device's current scroll mode (0 = tactile, 1 = free spin) + :rtype: int + """ + self.logger.debug("DBus call get_scroll_mode") + + driver_path = self.get_driver_path('scroll_mode') + + with open(driver_path, 'r') as driver_file: + return int(driver_file.read().strip()) + + +@endpoint('razer.device.scroll', 'setScrollAcceleration', in_sig='b') +def set_scroll_acceleration(self, enabled): + """ + Set the device's scroll acceleration state + + :param enabled: true to enable acceleration, false to disable it + :type enabled: bool + """ + self.logger.debug("DBus call set_scroll_acceleration") + + driver_path = self.get_driver_path('scroll_acceleration') + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(int(enabled))) + + +@endpoint('razer.device.scroll', 'getScrollAcceleration', out_sig='b') +def get_scroll_acceleration(self): + """ + Get the device's scroll acceleration state + + :return: true if acceleration enabled, false otherwise + :rtype: bool + """ + self.logger.debug("DBus call get_scroll_acceleration") + + driver_path = self.get_driver_path('scroll_acceleration') + + with open(driver_path, 'r') as driver_file: + return bool(int(driver_file.read().strip())) + + +@endpoint('razer.device.scroll', 'setScrollSmartReel', in_sig='b') +def set_scroll_smart_reel(self, enabled): + """ + Set the device's "smart reel" state + + :param enabled: true to enable smart reel, false to disable it + :type enabled: bool + """ + self.logger.debug("DBus call set_scroll_smart_reel") + + driver_path = self.get_driver_path('scroll_smart_reel') + + with open(driver_path, 'w') as driver_file: + driver_file.write(str(int(enabled))) + + +@endpoint('razer.device.scroll', 'getScrollSmartReel', out_sig='b') +def get_scroll_smart_reel(self): + """ + Get the device's "smart reel" state + + :return: true if smart reel enabled, false otherwise + :rtype: bool + """ + self.logger.debug("DBus call get_scroll_smart_reel") + + driver_path = self.get_driver_path('scroll_smart_reel') + + with open(driver_path, 'r') as driver_file: + return bool(int(driver_file.read().strip())) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/nagahex.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/nagahex.py new file mode 100644 index 00000000..40f3beac --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/nagahex.py @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Naga Hex DPI +""" +import struct +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.dpi', 'setDPI', in_sig='qq') +def set_dpi_xy_byte(self, dpi_x, dpi_y): + """ + Set the DPI on the mouse, Takes in 4 bytes big-endian and converts it to bytes + + :param dpi_x: X DPI + :type dpi_x: int + :param dpi_y: Y DPI + :type dpi_x: int + """ + self.logger.debug("DBus call set_dpi_xy_byte") + + # check that DPI is not more than the maximum + if dpi_x > self.DPI_MAX: + raise RuntimeError("Provided DPI " + str(dpi_x) + " is larger than maximum of " + str(self.DPI_MAX)) + if dpi_y > self.DPI_MAX: + raise RuntimeError("Provided DPI " + str(dpi_x) + " is larger than maximum of " + str(self.DPI_MAX)) + + driver_path = self.get_driver_path('dpi') + + if dpi_x > 6750: + dpi_x = 6750 + elif dpi_x < 100: + dpi_x = 100 + if dpi_y > 6750: + dpi_y = 6750 + elif dpi_y < 100: + dpi_y = 100 + + dpi_x_scaled = int(round(dpi_x / 6750 * 255, 2)) + dpi_y_scaled = int(round(dpi_y / 6750 * 255, 2)) + + self.dpi[0] = dpi_x + self.dpi[1] = dpi_y + + self.set_persistence(None, "dpi_x", dpi_x_scaled) + self.set_persistence(None, "dpi_y", dpi_y_scaled) + + if self._testing: + with open(driver_path, 'w') as driver_file: + driver_file.write("{}:{}".format(dpi_x_scaled, dpi_y_scaled)) + return + + dpi_bytes = struct.pack('>BB', dpi_x_scaled, dpi_y_scaled) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(dpi_bytes) + + +@endpoint('razer.device.dpi', 'getDPI', out_sig='ai') +def get_dpi_xy_byte(self): + """ + get the DPI on the mouse + + :return: List of X, Y DPI + :rtype: list of int + """ + self.logger.debug("DBus call get_dpi_xy_byte") + + driver_path = self.get_driver_path('dpi') + + # try retrieving DPI from the hardware. + # if we can't (e.g. because the mouse has been disconnected) + # return the value in local storage. + try: + with open(driver_path, 'r') as driver_file: + result = driver_file.read() + dpi_x, dpi_y = [int(dpi) for dpi in result.strip().split(':')] + dpi_x = int(round(dpi_x / 255 * 6750, 2)) + dpi_y = int(round(dpi_y / 255 * 6750, 2)) + except FileNotFoundError: + dpi_x, dpi_y = self.dpi + + return [dpi_x, dpi_y] diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/nagahexv2.py b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/nagahexv2.py new file mode 100644 index 00000000..ba7229ad --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/dbus_methods/nagahexv2.py @@ -0,0 +1,536 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +from openrazer_daemon.dbus_services import endpoint + + +@endpoint('razer.device.lighting.logo', 'setLogoStatic', in_sig='yyy') +def set_logo_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_static_effect") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("logo", "effect", 'static') + self.zone["logo"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('logo_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.logo', 'setLogoSpectrum') +def set_logo_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_logo_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + # remember effect + self.set_persistence("logo", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('logo_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.logo', 'setLogoNone') +def set_logo_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_none_effect") + + # Notify others + self.send_effect_event('setNone') + + # remember effect + self.set_persistence("logo", "effect", 'none') + + driver_path = self.get_driver_path('logo_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.logo', 'setLogoOn') +def set_logo_on(self): + """ + Set the device to effect on + """ + self.logger.debug("DBus call set_logo_on") + + # Notify others + self.send_effect_event('setOn') + + # remember effect + self.set_persistence("logo", "effect", 'on') + + driver_path = self.get_driver_path('logo_matrix_effect_on') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.logo', 'setLogoReactive', in_sig='yyyy') +def set_logo_reactive(self, red, green, blue, speed): + """ + Set the device to reactive effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + + :param speed: Speed + :type speed: int + """ + self.logger.debug("DBus call set_reactive_effect") + + driver_path = self.get_driver_path('logo_matrix_effect_reactive') + + # Notify others + self.send_effect_event('setReactive', red, green, blue, speed) + + # remember effect + self.set_persistence("logo", "effect", 'reactive') + self.zone["logo"]["colors"][0:3] = int(red), int(green), int(blue) + self.set_persistence("logo", "speed", int(speed)) + + if speed not in (1, 2, 3, 4): + speed = 4 + + payload = bytes([speed, red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.logo', 'setLogoBreathMono') +def set_logo_breath_mono(self): + """ + Set the device to mono colour breathing effect + """ + self.logger.debug("DBus call set_logo_breath_mono") + + # Notify others + self.send_effect_event('setBreathMono') + + # remember effect + self.set_persistence("logo", "effect", 'breathMono') + + driver_path = self.get_driver_path('logo_matrix_effect_breath') + + with open(driver_path, 'wb') as driver_file: + driver_file.write(b'1') + + +@endpoint('razer.device.lighting.logo', 'setLogoBreathRandom') +def set_logo_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_breath_random_effect") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("logo", "effect", 'breathRandom') + + driver_path = self.get_driver_path('logo_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.logo', 'setLogoBreathSingle', in_sig='yyy') +def set_logo_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_breath_single_effect") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("logo", "effect", 'breathSingle') + self.zone["logo"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('logo_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.logo', 'setLogoBreathDual', in_sig='yyyyyy') +def set_logo_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_breath_dual_effect") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("logo", "effect", 'breathDual') + self.zone["logo"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('logo_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.logo', 'setLogoBlinking', in_sig='yyy') +def set_logo_blinking(self, red, green, blue): + """ + Set the device to blinking mode + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_logo_blinking") + + # Notify others + self.send_effect_event('setBlinking', red, green, blue) + + # remember effect + self.set_persistence("logo", "effect", 'blinking') + self.zone["logo"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('logo_matrix_effect_blinking') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.scroll', 'setScrollStatic', in_sig='yyy') +def set_scroll_static(self, red, green, blue): + """ + Set the device to static colour + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_static_effect") + + # Notify others + self.send_effect_event('setStatic', red, green, blue) + + # remember effect + self.set_persistence("scroll", "effect", 'static') + self.zone["scroll"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('scroll_matrix_effect_static') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) + + +@endpoint('razer.device.lighting.scroll', 'setScrollSpectrum') +def set_scroll_spectrum(self): + """ + Set the device to spectrum mode + """ + self.logger.debug("DBus call set_scroll_spectrum") + + # Notify others + self.send_effect_event('setSpectrum') + + self.set_persistence("scroll", "effect", 'spectrum') + + effect_driver_path = self.get_driver_path('scroll_matrix_effect_spectrum') + + with open(effect_driver_path, 'w') as effect_driver_file: + effect_driver_file.write('1') + + +@endpoint('razer.device.lighting.scroll', 'setScrollNone') +def set_scroll_none(self): + """ + Set the device to effect none + """ + self.logger.debug("DBus call set_none_effect") + + # Notify others + self.send_effect_event('setNone') + + self.set_persistence("scroll", "effect", 'none') + + driver_path = self.get_driver_path('scroll_matrix_effect_none') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.scroll', 'setScrollOn') +def set_scroll_on(self): + """ + Set the device to effect on + """ + self.logger.debug("DBus call set_scroll_on") + + # Notify others + self.send_effect_event('setOn') + + self.set_persistence("scroll", "effect", 'on') + + driver_path = self.get_driver_path('scroll_matrix_effect_on') + + with open(driver_path, 'w') as driver_file: + driver_file.write('1') + + +@endpoint('razer.device.lighting.scroll', 'setScrollReactive', in_sig='yyyy') +def set_scroll_reactive(self, red, green, blue, speed): + """ + Set the device to reactive effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + + :param speed: Speed + :type speed: int + """ + self.logger.debug("DBus call set_reactive_effect") + + driver_path = self.get_driver_path('scroll_matrix_effect_reactive') + + # Notify others + self.send_effect_event('setReactive', red, green, blue, speed) + + # remember effect + self.set_persistence("scroll", "effect", 'reactive') + self.zone["scroll"]["colors"][0:3] = int(red), int(green), int(blue) + self.set_persistence("scroll", "speed", int(speed)) + + if speed not in (1, 2, 3, 4): + speed = 4 + + payload = bytes([speed, red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.scroll', 'setScrollBreathMono') +def set_scroll_breath_mono(self): + """ + Set the device to mono colour breathing effect + """ + self.logger.debug("DBus call set_scroll_breath_mono") + + # Notify others + self.send_effect_event('setBreathMono') + + # remember effect + self.set_persistence("scroll", "effect", 'breathMono') + + driver_path = self.get_driver_path('scroll_matrix_effect_breath') + + with open(driver_path, 'wb') as driver_file: + driver_file.write(b'1') + + +@endpoint('razer.device.lighting.scroll', 'setScrollBreathRandom') +def set_scroll_breath_random(self): + """ + Set the device to random colour breathing effect + """ + self.logger.debug("DBus call set_breath_random_effect") + + # Notify others + self.send_effect_event('setBreathRandom') + + # remember effect + self.set_persistence("scroll", "effect", 'breathRandom') + + driver_path = self.get_driver_path('scroll_matrix_effect_breath') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.scroll', 'setScrollBreathSingle', in_sig='yyy') +def set_scroll_breath_single(self, red, green, blue): + """ + Set the device to single colour breathing effect + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_breath_single_effect") + + # Notify others + self.send_effect_event('setBreathSingle', red, green, blue) + + # remember effect + self.set_persistence("scroll", "effect", 'breathSingle') + self.zone["scroll"]["colors"][0:3] = int(red), int(green), int(blue) + + driver_path = self.get_driver_path('scroll_matrix_effect_breath') + + payload = bytes([red, green, blue]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.scroll', 'setScrollBreathDual', in_sig='yyyyyy') +def set_scroll_breath_dual(self, red1, green1, blue1, red2, green2, blue2): + """ + Set the device to dual colour breathing effect + + :param red1: Red component + :type red1: int + + :param green1: Green component + :type green1: int + + :param blue1: Blue component + :type blue1: int + + :param red2: Red component + :type red2: int + + :param green2: Green component + :type green2: int + + :param blue2: Blue component + :type blue2: int + """ + self.logger.debug("DBus call set_breath_dual_effect") + + # Notify others + self.send_effect_event('setBreathDual', red1, green1, blue1, red2, green2, blue2) + + # remember effect + self.set_persistence("scroll", "effect", 'breathDual') + self.zone["scroll"]["colors"][0:6] = int(red1), int(green1), int(blue1), int(red2), int(green2), int(blue2) + + driver_path = self.get_driver_path('scroll_matrix_effect_breath') + + payload = bytes([red1, green1, blue1, red2, green2, blue2]) + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + +@endpoint('razer.device.lighting.scroll', 'setScrollBlinking', in_sig='yyy') +def set_scroll_blinking(self, red, green, blue): + """ + Set the device to blinking mode + + :param red: Red component + :type red: int + + :param green: Green component + :type green: int + + :param blue: Blue component + :type blue: int + """ + self.logger.debug("DBus call set_scroll_blinking") + + # Notify others + self.send_effect_event('setBlinking', red, green, blue) + + # remember effect + self.set_persistence("scroll", "effect", 'blinking') + self.zone["scroll"]["colors"][0:3] = int(red), int(green), int(blue) + + rgb_driver_path = self.get_driver_path('scroll_matrix_effect_blinking') + + payload = bytes([red, green, blue]) + + with open(rgb_driver_path, 'wb') as rgb_driver_file: + rgb_driver_file.write(payload) diff --git a/openrazer/daemon/openrazer_daemon/dbus_services/service.py b/openrazer/daemon/openrazer_daemon/dbus_services/service.py new file mode 100644 index 00000000..8c89bf95 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/dbus_services/service.py @@ -0,0 +1,119 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Service Object for DBus +""" + +# Disable some pylint stuff +# pylint: disable=no-member + +import types +import dbus +import dbus.service + + +def copy_func(function_reference, name=None): + """ + Copy function + + :param function_reference: Function + :type function_reference: func + + :param name: Name of function + :type name: str + + :return: Copy of function + :rtype: func + """ + if hasattr(function_reference, 'code'): + return types.FunctionType(function_reference.code, function_reference.globals, name or function_reference.func_name, function_reference.defaults, function_reference.closure) + else: + return types.FunctionType(function_reference.__code__, function_reference.__globals__, name or function_reference.func_name, function_reference.__defaults__, function_reference.__closure__) + + +class DBusService(dbus.service.Object): + """ + DBus Service object + + Allows for dynamic method adding + """ + BUS_NAME = 'org.razer' + + def __init__(self, object_path): + """ + Init the object + + :param object_path: DBus Object name + :type object_path: str + """ + # We could pass (bus, object_path) here, but we rather register the object manually. + super().__init__() + + bus = dbus.SessionBus() + + # the constructor of BusName registers the bus, the returned object is not used but must be kept + self.bus_name_obj = dbus.service.BusName(self.BUS_NAME, bus) + + self.add_to_connection(bus, object_path) + + def add_dbus_method(self, interface_name, function_name, function, in_signature=None, out_signature=None, byte_arrays=False): + """ + Add method to DBus Object + + :param interface_name: DBus interface name + :type interface_name: str + + :param function_name: DBus function name + :type function_name: str + + :param function: Function reference + :type function: object + + :param in_signature: DBus function signature + :type in_signature: str + + :param out_signature: DBus function signature + :type out_signature: str + + :param byte_arrays: Is byte array + :type byte_arrays: bool + """ + + # Get class key for use in the DBus introspection table + class_key = [key for key in self._dbus_class_table.keys() if key.endswith(self.__class__.__name__)][0] + + # Create a copy of the function so that if its used multiple times it won't affect other instances if the names changed + function_deepcopy = copy_func(function, function_name) + func = dbus.service.method(interface_name, in_signature=in_signature, out_signature=out_signature, byte_arrays=byte_arrays)(function_deepcopy) + + # Add method to DBus tables + try: + self._dbus_class_table[class_key][interface_name][function_name] = func + except KeyError: + self._dbus_class_table[class_key][interface_name] = {function_name: func} + + # Add method to class as DBus expects it to be there. + setattr(self.__class__, function_name, func) + + def del_dbus_method(self, interface_name, function_name): + """ + Remove method from DBus Object + + :param interface_name: DBus interface name + :type interface_name: str + + :param function_name: DBus function name + :type function_name: str + """ + + # Get class key for use in the DBus introspection table + class_key = [key for key in self._dbus_class_table.keys() if key.endswith(self.__class__.__name__)][0] + + # Remove method from DBus tables + # Remove method from class + try: + del self._dbus_class_table[class_key][interface_name][function_name] + delattr(DBusService, function_name) + + except (KeyError, AttributeError): + pass diff --git a/openrazer/daemon/openrazer_daemon/device.py b/openrazer/daemon/openrazer_daemon/device.py new file mode 100644 index 00000000..799b420b --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/device.py @@ -0,0 +1,248 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Class to hold a device and collections of them +""" + + +class Device(object): + """ + Razer Device (High level not dbus) + """ + + def __init__(self, device_id, device_serial, device_dbus_object): + self._parent = None + + self._id = device_id + self._serial = device_serial + self._dbus = device_dbus_object + # Register as parent + self._dbus.register_parent(self) + + @property + def device_id(self): + """ + Device's USB ID String + + :return: Device ID + :rtype: str + """ + return self._id + + @property + def serial(self): + """ + Device's Serial String + + :return: Serial + :rtype: str + """ + return self._serial + + @property + def dbus(self): + """ + Device's DBus object + + :return: DBus Object + :rtype: openrazer_daemon.hardware.device_base.__RazerDevice + """ + return self._dbus + + def register_parent(self, parent): + """ + Register the parent as an observer to be optionally notified (sends to other devices) + + :param parent: Observer + :type parent: object + """ + self._parent = parent + + def notify_parent(self, msg): + """ + Notify observers with msg + + :param msg: Tuple with first element a string + :type msg: tuple + """ + self._parent.notify(self, msg) + + def notify_child(self, msg): + """ + Receive observer messages + + :param msg: Tuple with first element a string + :type msg: tuple + """ + # Message from DBus object + self._dbus.notify(msg) + + +class DeviceCollection(object): + """ + Multimap of devices + + Can be referenced by either ID or serial + """ + + def __init__(self): + self._id_map = {} + self._serial_map = {} + + def add(self, device_id, device_serial, device_dbus): + """ + Add device to collection + + :param device_id: Device's USB ID + :type device_id: str + + :param device_serial: Device's Serial String + :type device_serial: str + + :param device_dbus: Device's DBus object + :type device_dbus: openrazer_daemon.hardware.device_base.__RazerDevice + """ + device_object = Device(device_id, device_serial, device_dbus) + device_object.register_parent(self) + + self._id_map[device_id] = device_object + self._serial_map[device_serial] = device_object + + def remove(self, key): + """ + Remove object being referenced to by ident from collection + + :param key: ID or serial + :type key: str + """ + self.__delitem__(key) + + def get(self, item): + """ + Get device object by ID or serial + + :param item: ID or serial + :type item: str + + :return: Device object + :rtype: Device + + :raises IndexError: If item not found + """ + return self.__getitem__(item) + + def id_items(self): + """ + Get (id, Device) iterator + + :return: Items method from the id map + :rtype: list of tuple of str, Device + """ + return self._id_map.items() + + def serial_items(self): + """ + Get (serial, Device) iterator + + :return: Items method from the serial map + :rtype: list of tuple of str, Device + """ + return self._serial_map.items() + + def serials(self): + """ + Get list of serials + + :return: Serial list + :rtype: list of str + """ + return list(self._serial_map.keys()) + + def __len__(self): + """ + Get length of collection + + :return: Length + :rtype: int + """ + return len(self._id_map) + + def __getitem__(self, item): + """ + Get device object by ID or serial + + :param item: ID or serial + :type item: str + + :return: Device object + :rtype: Device + + :raises IndexError: If item not found + """ + if item in self._id_map: + return self._id_map[item] + elif item in self._serial_map: + return self._serial_map[item] + else: + raise IndexError() + + def __delitem__(self, key): + """ + Remove object being referenced to by ident from collection + + :param key: ID or serial + :type key: str + """ + if key in self._id_map: + serial = self._id_map[key].serial + self._id_map.pop(key, None) + self._serial_map.pop(serial, None) + elif key in self._serial_map: + device_id = self._serial_map[key].device_id + self._id_map.pop(device_id, None) + self._serial_map.pop(key, None) + + def __contains__(self, item): + """ + If ID or serial exists in datastructure + + :param item: ID or serial + :type item: str + + :return: True if ID or serial exists + :rtype: bool + """ + return item in self._id_map or item in self._serial_map + + def __iter__(self): + """ + Get devices + + :return: Devices + :rtype: list of Device + """ + return iter(self._id_map.values()) + + @property + def devices(self): + """ + Get device list + + :return: List of devices + :rtype: list of Device + """ + return list(self._id_map.values()) + + def notify(self, active_child, msg): + """ + Send messages between children + + :param active_child: Child sending the message + :type active_child: Device + + :param msg: Messgae + :type msg: tuple + """ + for child in self._id_map.values(): + if child is not active_child: + child.notify_child(msg) diff --git a/openrazer/daemon/openrazer_daemon/hardware/__init__.py b/openrazer/daemon/openrazer_daemon/hardware/__init__.py new file mode 100644 index 00000000..2191011f --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/__init__.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Hardware collection +""" +import os +from openrazer_daemon.hardware.device_base import RazerDevice + +# Hack to get a list of hardware modules to import +HARDWARE_MODULES = ['openrazer_daemon.hardware.' + os.path.splitext(hw_file)[0] for hw_file in os.listdir(os.path.dirname(__file__)) if hw_file not in ('device_base.py', '__init__.py') and hw_file.endswith('.py')] + +# List of classes to exclude from the class finding +EXCLUDED_CLASSES = ('RazerDevice', 'RazerDeviceBrightnessSuspend') + + +def get_device_classes(): + """ + Get a list of hardware classes + + :return: List of RazerDevice subclasses + :rtype: list of callable + """ + classes = [] + + for hw_module in HARDWARE_MODULES: + imported_module = __import__(hw_module, globals=globals(), locals=locals(), fromlist=['*'], level=0) + + for class_name, class_instance in imported_module.__dict__.items(): + if class_name in EXCLUDED_CLASSES or class_name.startswith('_') or not isinstance(class_instance, type): + continue + + classes.append(class_instance) + + return sorted(classes, key=lambda cls: cls.__name__) diff --git a/openrazer/daemon/openrazer_daemon/hardware/accessory.py b/openrazer/daemon/openrazer_daemon/hardware/accessory.py new file mode 100644 index 00000000..e6781bbe --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/accessory.py @@ -0,0 +1,232 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Mug class +""" +import re + +from openrazer_daemon.hardware.device_base import RazerDeviceBrightnessSuspend as _RazerDeviceBrightnessSuspend + + +class RazerChromaMugHolder(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Chroma Mug Holder + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Chroma_Mug_Holder-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0F07 + HAS_MATRIX = True + MATRIX_DIMS = [1, 15] + METHODS = ['get_device_type_accessory', + 'set_static_effect', 'set_spectrum_effect', 'set_wave_effect', 'set_none_effect', 'set_breath_single_effect', 'set_breath_dual_effect', 'set_breath_random_effect', 'set_blinking_effect', + 'is_mug_present', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/mug-holder/e64e507b73e61c44789d996065fd9645-1500x1000mug_01.jpg" + + +class RazerChromaARGB(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Chroma Addressable RGB Controller + """ + USB_VID = 0x1532 + USB_PID = 0x0F1F + HAS_MATRIX = True + MATRIX_DIMS = [6, 80] + NUM_CHANNELS = 6 + WAVE_DIRS = (1, 2) + METHODS = ['get_device_type_accessory', + 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', + 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', + 'get_num_channels', + 'get_channel_brightness', 'set_channel_brightness', + 'get_channel_size', 'set_channel_size'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/3903-1-EN-v1.png" + + +class RazerChromaHDK(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Chroma Hardware Development Kit (HDK) + """ + USB_VID = 0x1532 + USB_PID = 0x0F09 + HAS_MATRIX = True + MATRIX_DIMS = [4, 16] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/chromahdk2017/788b689d471fedbc0c5a175592316657-gallery-08.jpg" + + +class RazerBaseStationChroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Base Station Chroma (Headphone Stand) + """ + USB_VID = 0x1532 + USB_PID = 0x0F08 + HAS_MATRIX = True + MATRIX_DIMS = [1, 15] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://rzrwarranty.s3.amazonaws.com/145dcc47f9f9d33b0bd07b066364704160f45e87b756d690b203decec7d1e87c.png" + + +class RazerMouseDock(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Mouse Dock + """ + USB_VID = 0x1532 + USB_PID = 0x007E + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + EVENT_FILE_REGEX = re.compile(r'.*Razer_Mouse_Dock-if0(1|2)-event-kbd') + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_spectrum_effect', 'set_brightness', + 'get_brightness', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1711/1711_-_mouse_dock_chroma.png" + + +class RazerNommoChroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Nommo Chroma (Speakers) + """ + USB_VID = 0x1532 + USB_PID = 0x0517 + HAS_MATRIX = True + MATRIX_DIMS = [2, 24] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1275/1275_nommo_chroma.png" + + +class RazerNommoPro(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Nommo Pro (Speakers) + """ + USB_VID = 0x1532 + USB_PID = 0x0518 + HAS_MATRIX = True + MATRIX_DIMS = [2, 8] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1419/1419_nommo_pro.png" + + +class RazerMouseBungeeV3Chroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Mouse Bungee V3 Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Mouse_Bungee_V3_Chroma-if01-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0F1D + HAS_MATRIX = True + MATRIX_DIMS = [1, 8] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/pnx.assets/03970e1bd220f3d2985c5e0060fb3bbf/razer-mouse-bungee-v3-chroma.png" + + +class RazerBaseStationV2Chroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Base Station V2 Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*RAZER_Razer_Base_Station_V2_Chroma-if01-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0F20 + HAS_MATRIX = True + MATRIX_DIMS = [1, 8] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/3897-1-EN-v2.png" + + +class RazerThunderbolt4DockChroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Thunderbolt 4 Dock Chroma + """ + USB_VID = 0x1532 + USB_PID = 0x0F21 + HAS_MATRIX = True + MATRIX_DIMS = [1, 12] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/4030-1-EN-v1.png" + + +class RazerChargingPadChroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Charging Pad Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*RAZER_Razer_Charging_Pad_Chroma-event-if01') + + USB_VID = 0x1532 + USB_PID = 0x0F26 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 10] + METHODS = ['get_device_type_accessory', 'set_custom_effect', 'set_key_row', 'get_charging_brightness', 'set_charging_brightness', 'get_fast_charging_brightness', 'set_fast_charging_brightness', 'get_fully_charged_brightness', 'set_fully_charged_brightness', + # Idle + 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + # Charging + 'set_charging_wave', 'set_charging_static', 'set_charging_spectrum', 'set_charging_none', 'set_charging_breath_random', 'set_charging_breath_single', 'set_charging_breath_dual', + # Fast Charging + 'set_fast_charging_wave', 'set_fast_charging_static', 'set_fast_charging_spectrum', 'set_fast_charging_none', 'set_fast_charging_breath_random', 'set_fast_charging_breath_single', 'set_fast_charging_breath_dual', + # Fully Charged + 'set_fully_charged_wave', 'set_fully_charged_static', 'set_fully_charged_spectrum', 'set_fully_charged_none', 'set_fully_charged_breath_random', 'set_fully_charged_breath_single', 'set_fully_charged_breath_dual'] + + DEVICE_IMAGE = "https://dl.razerzone.com/Images/ChargingPadChroma/CPC-ProductImage.png" + + +class RazerLaptopStandChroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Laptop Stand Chroma + """ + + USB_VID = 0x1532 + USB_PID = 0x0F0D + HAS_MATRIX = True + MATRIX_DIMS = [1, 16] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/hfe/hbc/9081459376158/Razer-Laptop-Stand-Chroma-04.jpg" + + +class RazerLaptopStandChromaV2(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Laptop Stand Chroma V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*RAZER_Razer_Laptop_Stand_Chroma_V2-event-if01') + + USB_VID = 0x1532 + USB_PID = 0x0F2B + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 15] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/pnx.assets/272c328913c00c6f584fe3dead2ca2a6/razer-laptop-stand-chroma-v2-hero-mobile-v2.jpg" diff --git a/openrazer/daemon/openrazer_daemon/hardware/core.py b/openrazer/daemon/openrazer_daemon/hardware/core.py new file mode 100644 index 00000000..56662fbd --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/core.py @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Core class +""" +from openrazer_daemon.hardware.device_base import RazerDeviceBrightnessSuspend as __RazerDeviceBrightnessSuspend + + +class RazerCore(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Core + """ + USB_VID = 0x1532 + USB_PID = 0x0215 + HAS_MATRIX = True + MATRIX_DIMS = [1, 9] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/684/684_razer_core.png" + + METHODS = ['set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'trigger_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_device_type_core'] + + +class RazerCoreXChroma(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Core X Chroma + """ + USB_VID = 0x1532 + USB_PID = 0x0F1A + HAS_MATRIX = True + MATRIX_DIMS = [1, 16] + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/h44/h3d/9084457943070/core-x-chroma-gallery1.jpg" + + METHODS = ['set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'trigger_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_device_type_core'] diff --git a/openrazer/daemon/openrazer_daemon/hardware/device_base.py b/openrazer/daemon/openrazer_daemon/hardware/device_base.py new file mode 100644 index 00000000..a2a44ca5 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/device_base.py @@ -0,0 +1,1337 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Hardware base class +""" +import configparser +import re +import os +import types +import inspect +import logging +import time +import json + +from openrazer_daemon.dbus_services.service import DBusService +import openrazer_daemon.dbus_services.dbus_methods +from openrazer_daemon.misc import effect_sync +from openrazer_daemon.misc.battery_notifier import BatteryManager as _BatteryManager + + +# pylint: disable=too-many-instance-attributes +# pylint: disable=E1102 +# See https://github.com/PyCQA/pylint/issues/1493 +class RazerDevice(DBusService): + """ + Base class + + Sets up the logger, sets up DBus + """ + OBJECT_PATH = '/org/razer/device/' + METHODS = [] + + EVENT_FILE_REGEX = None + + USB_VID = None + USB_PID = None + HAS_MATRIX = False + DEDICATED_MACRO_KEYS = False + MATRIX_DIMS = None + POLL_RATES = None + DPI_MAX = None + DRIVER_MODE = False + + WAVE_DIRS = (1, 2) + + ZONES = ('backlight', 'logo', 'scroll', 'left', 'right', 'charging', 'fast_charging', 'fully_charged', 'channel1', 'channel2', 'channel3', 'channel4', 'channel5', 'channel6') + + DEVICE_IMAGE = None + + def __init__(self, device_path, device_number, config, persistence, testing, additional_interfaces, additional_methods, unknown_serial_counter): + + self.logger = logging.getLogger('razer.device{0}'.format(device_number)) + self.logger.info("Initialising device.%d %s", device_number, self.__class__.__name__) + + # Serial cache + self._serial = None + + # map of vid+pid to counter for serial numbers for unknown devices + self._unknown_serial_counter: dict[tuple[int, int], int] = unknown_serial_counter + + # Local storage key name + self.storage_name = "UnknownDevice" + + self._observer_list = [] + self._effect_sync_propagate_up = False + self._disable_notifications = False + self._disable_persistence = False + self.additional_interfaces = [] + if additional_interfaces is not None: + self.additional_interfaces.extend(additional_interfaces) + self._battery_manager = None + + self.config = config + self.persistence = persistence + self._testing = testing + self._parent = None + self._device_path = device_path + self._device_number = device_number + self.serial = self.get_serial() + + if self.USB_PID == 0x0f07: + self.storage_name = "ChromaMug" + elif self.USB_PID == 0x0013: + self.storage_name = "Orochi2011" + elif self.USB_PID == 0x0016: + self.storage_name = "DeathAdder35G" + elif self.USB_PID == 0x0029: + self.storage_name = "DeathAdder35GBlack" + elif self.USB_PID == 0x0024 or self.USB_PID == 0x0025: + self.storage_name = "Mamba2012" + else: + self.storage_name = self.serial + + self.zone = dict() + + for i in self.ZONES: + self.zone[i] = { + "present": False, + "active": True, + "brightness": 75.0, + "effect": 'spectrum', + "colors": [0, 255, 0, 0, 255, 255, 0, 0, 255], + "speed": 1, + "wave_dir": 1, + } + + # Check for a DPI X only device since they need a Y value of 0 + if 'available_dpi' in self.METHODS: + self.dpi = [1800, 0] + else: + self.dpi = [1800, 1800] + + self.poll_rate = 500 + if 'set_poll_rate' in self.METHODS and not self.POLL_RATES: + self.POLL_RATES = [125, 500, 1000] + + self._effect_sync = effect_sync.EffectSync(self, device_number) + + self._is_closed = False + + # device methods available in all devices + self.methods_internal = ['get_firmware', 'get_matrix_dims', 'has_matrix', 'get_device_name'] + self.methods_internal.extend(additional_methods) + + # Find event files in /dev/input/by-id/ by matching against regex + self.event_files = [] + + if self._testing: + search_dir = os.path.join(device_path, 'input') + else: + search_dir = '/dev/input/by-id/' + + if os.path.exists(search_dir): + for event_file in os.listdir(search_dir): + if self.EVENT_FILE_REGEX is not None and self.EVENT_FILE_REGEX.match(event_file) is not None: + self.event_files.append(os.path.join(search_dir, event_file)) + + object_path = os.path.join(self.OBJECT_PATH, self.serial) + super().__init__(object_path) + + # Set up methods to suspend and restore device operation + self.suspend_args = {} + self.method_args = {} + + methods = { + # interface, method, callback, in-args, out-args + ('razer.device.misc', 'getSerial', self.get_serial, None, 's'), + ('razer.device.misc', 'suspendDevice', self.suspend_device, None, None), + ('razer.device.misc', 'getDeviceMode', self.get_device_mode, None, 's'), + ('razer.device.misc', 'getDeviceImage', self.get_device_image, None, 's'), + ('razer.device.misc', 'setDeviceMode', self.set_device_mode, 'yy', None), + ('razer.device.misc', 'resumeDevice', self.resume_device, None, None), + ('razer.device.misc', 'getVidPid', self.get_vid_pid, None, 'ai'), + ('razer.device.misc', 'getDriverVersion', openrazer_daemon.dbus_services.dbus_methods.version, None, 's'), + ('razer.device.misc', 'hasDedicatedMacroKeys', self.dedicated_macro_keys, None, 'b'), + # Deprecated API, but kept for backwards compatibility + ('razer.device.misc', 'getRazerUrls', self.get_image_json, None, 's'), + + ('razer.device.lighting.chroma', 'restoreLastEffect', self.restore_effect, None, None), + } + + effect_methods = { + "backlight_chroma": { + ('razer.device.lighting.chroma', 'getEffect', self.get_current_effect, None, 's'), + ('razer.device.lighting.chroma', 'getEffectColors', self.get_current_effect_colors, None, 'ay'), + ('razer.device.lighting.chroma', 'getEffectSpeed', self.get_current_effect_speed, None, 'i'), + ('razer.device.lighting.chroma', 'getWaveDir', self.get_current_wave_dir, None, 'i'), + }, + + "backlight": { + # Intentionally using the same underlying methods as backlight_chroma. + # Both refer to the 'backlight' LED internally but partially exist separately due to historical reasons. + ('razer.device.lighting.backlight', 'getBacklightEffect', self.get_current_effect, None, 's'), + ('razer.device.lighting.backlight', 'getBacklightEffectColors', self.get_current_effect_colors, None, 'ay'), + ('razer.device.lighting.backlight', 'getBacklightEffectSpeed', self.get_current_effect_speed, None, 'i'), + ('razer.device.lighting.backlight', 'getBacklightWaveDir', self.get_current_wave_dir, None, 'i'), + }, + + "logo": { + ('razer.device.lighting.logo', 'getLogoEffect', self.get_current_logo_effect, None, 's'), + ('razer.device.lighting.logo', 'getLogoEffectColors', self.get_current_logo_effect_colors, None, 'ay'), + ('razer.device.lighting.logo', 'getLogoEffectSpeed', self.get_current_logo_effect_speed, None, 'i'), + ('razer.device.lighting.logo', 'getLogoWaveDir', self.get_current_logo_wave_dir, None, 'i'), + }, + + "scroll": { + ('razer.device.lighting.scroll', 'getScrollEffect', self.get_current_scroll_effect, None, 's'), + ('razer.device.lighting.scroll', 'getScrollEffectColors', self.get_current_scroll_effect_colors, None, 'ay'), + ('razer.device.lighting.scroll', 'getScrollEffectSpeed', self.get_current_scroll_effect_speed, None, 'i'), + ('razer.device.lighting.scroll', 'getScrollWaveDir', self.get_current_scroll_wave_dir, None, 'i'), + }, + + "left": { + ('razer.device.lighting.left', 'getLeftEffect', self.get_current_left_effect, None, 's'), + ('razer.device.lighting.left', 'getLeftEffectColors', self.get_current_left_effect_colors, None, 'ay'), + ('razer.device.lighting.left', 'getLeftEffectSpeed', self.get_current_left_effect_speed, None, 'i'), + ('razer.device.lighting.left', 'getLeftWaveDir', self.get_current_left_wave_dir, None, 'i'), + }, + + "right": { + ('razer.device.lighting.right', 'getRightEffect', self.get_current_right_effect, None, 's'), + ('razer.device.lighting.right', 'getRightEffectColors', self.get_current_right_effect_colors, None, 'ay'), + ('razer.device.lighting.right', 'getRightEffectSpeed', self.get_current_right_effect_speed, None, 'i'), + ('razer.device.lighting.right', 'getRightWaveDir', self.get_current_right_wave_dir, None, 'i'), + }, + + "charging": { + ('razer.device.lighting.charging', 'getChargingEffect', self.get_current_charging_effect, None, 's'), + ('razer.device.lighting.charging', 'getChargingEffectColors', self.get_current_charging_effect_colors, None, 'ay'), + ('razer.device.lighting.charging', 'getChargingEffectSpeed', self.get_current_charging_effect_speed, None, 'i'), + ('razer.device.lighting.charging', 'getChargingWaveDir', self.get_current_charging_wave_dir, None, 'i'), + }, + + "fast_charging": { + ('razer.device.lighting.fast_charging', 'getFastChargingEffect', self.get_current_fast_charging_effect, None, 's'), + ('razer.device.lighting.fast_charging', 'getFastChargingEffectColors', self.get_current_fast_charging_effect_colors, None, 'ay'), + ('razer.device.lighting.fast_charging', 'getFastChargingEffectSpeed', self.get_current_fast_charging_effect_speed, None, 'i'), + ('razer.device.lighting.fast_charging', 'getFastChargingWaveDir', self.get_current_fast_charging_wave_dir, None, 'i'), + }, + + "fully_charged": { + ('razer.device.lighting.fully_charged', 'getFullyChargedEffect', self.get_current_fully_charged_effect, None, 's'), + ('razer.device.lighting.fully_charged', 'getFullyChargedEffectColors', self.get_current_fully_charged_effect_colors, None, 'ay'), + ('razer.device.lighting.fully_charged', 'getFullyChargedEffectSpeed', self.get_current_fully_charged_effect_speed, None, 'i'), + ('razer.device.lighting.fully_charged', 'getFullyChargedWaveDir', self.get_current_fully_charged_wave_dir, None, 'i'), + } + } + + for m in methods: + self.logger.debug("Adding {}.{} method to DBus".format(m[0], m[1])) + self.add_dbus_method(m[0], m[1], m[2], in_signature=m[3], out_signature=m[4]) + + # this check is separate from the rest because backlight effects don't have prefixes in their names + if 'set_static_effect' in self.METHODS or 'bw_set_static' in self.METHODS: + self.zone["backlight"]["present"] = True + for m in effect_methods["backlight_chroma"]: + self.logger.debug("Adding {}.{} method to DBus".format(m[0], m[1])) + self.add_dbus_method(m[0], m[1], m[2], in_signature=m[3], out_signature=m[4]) + + for i in self.ZONES: + if 'set_' + i + '_static_classic' in self.METHODS \ + or 'set_' + i + '_static' in self.METHODS \ + or 'set_' + i + '_active' in self.METHODS \ + or 'set_' + i + '_on' in self.METHODS: + self.zone[i]["present"] = True + for m in effect_methods[i]: + self.logger.debug("Adding {}.{} method to DBus".format(m[0], m[1])) + self.add_dbus_method(m[0], m[1], m[2], in_signature=m[3], out_signature=m[4]) + + # Load additional DBus methods + self.load_methods() + + # load last DPI/poll rate state + if self.persistence.has_section(self.storage_name): + if 'set_dpi_xy' in self.METHODS or 'set_dpi_xy_byte' in self.METHODS: + try: + self.dpi[0] = int(self.persistence[self.storage_name]['dpi_x']) + self.dpi[1] = int(self.persistence[self.storage_name]['dpi_y']) + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get DPI from persistence storage, using default.") + + if 'set_poll_rate' in self.METHODS: + try: + self.poll_rate = int(self.persistence[self.storage_name]['poll_rate']) + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get poll rate from persistence storage, using default.") + + # load last effects + for i in self.ZONES: + if self.zone[i]["present"]: + # check if we have the device in the persistence file + if self.persistence.has_section(self.storage_name): + # try reading the effect name from the persistence + try: + self.zone[i]["effect"] = self.persistence[self.storage_name][i + '_effect'] + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get " + i + " effect from persistence storage, using default.") + + # zone active status + try: + self.zone[i]["active"] = self.persistence.getboolean(self.storage_name, i + '_active') + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get " + i + " active from persistence storage, using default.") + + # brightness + try: + self.zone[i]["brightness"] = float(self.persistence[self.storage_name][i + '_brightness']) + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get " + i + " brightness from persistence storage, using default.") + + # colors. + # these are stored as a string that must contain 9 numbers, separated with spaces. + try: + for index, item in enumerate(self.persistence[self.storage_name][i + '_colors'].split(" ")): + self.zone[i]["colors"][index] = int(item) + # check if the color is in range + if not 0 <= self.zone[i]["colors"][index] <= 255: + raise ValueError('Color out of range') + + # check if we have exactly 9 colors + if len(self.zone[i]["colors"]) != 9: + raise ValueError('There must be exactly 9 colors') + except ValueError: + # invalid colors. reinitialize + self.zone[i]["colors"] = [0, 255, 0, 0, 255, 255, 0, 0, 255] + self.logger.info("%s: Invalid colors; restoring to defaults.", self.__class__.__name__) + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get " + i + " colors from persistence storage, using default.") + + # speed + try: + self.zone[i]["speed"] = int(self.persistence[self.storage_name][i + '_speed']) + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get " + i + " speed from persistence storage, using default.") + + # wave direction + try: + self.zone[i]["wave_dir"] = int(self.persistence[self.storage_name][i + '_wave_dir']) + except (KeyError, configparser.NoOptionError): + self.logger.info("Failed to get " + i + " wave direction from persistence storage, using default.") + + # Initialize battery manager if the device has support + if 'get_battery' in self.METHODS: + self._init_battery_manager() + + if self.DRIVER_MODE: + self.logger.info('Setting device to "driver" mode. Daemon will handle special functionality') + self.set_device_mode(0x03, 0x00) # Driver mode + + self.restore_dpi_poll_rate() + self.restore_brightness() + + if self.config.getboolean('Startup', "restore_persistence") is True: + self.restore_effect() + + # Some devices need setting a second time after encountering Razer Synapse on Windows + if self.config.getboolean('Startup', "persistence_dual_boot_quirk") is True: + self.logger.debug("Restoring effect persistence again (dual boot quirk)") + self.restore_effect() + + def send_effect_event(self, effect_name, *args): + """ + Send effect event + + :param effect_name: Effect name + :type effect_name: str + + :param args: Effect arguments + :type args: list + """ + payload = ['effect', self, effect_name] + payload.extend(args) + + self.notify_observers(tuple(payload)) + + def dedicated_macro_keys(self): + """ + Returns if the device has dedicated macro keys + + :return: Macro keys + :rtype: bool + """ + return self.DEDICATED_MACRO_KEYS + + def restore_dpi_poll_rate(self): + """ + Set the device DPI & poll rate to the saved value + """ + dpi_func = getattr(self, "setDPI", None) + if dpi_func is not None: + # Constrain value in case the max has changed, e.g. wired/wireless might different maximums + if self.dpi[0] > self.DPI_MAX: + self.logger.warning("Constraining DPI X to maximum of " + str(self.DPI_MAX) + " because stored value " + str(self.dpi[0]) + " is larger.") + self.dpi[0] = self.DPI_MAX + if self.dpi[1] > self.DPI_MAX: + self.logger.warning("Constraining DPI Y to maximum of " + str(self.DPI_MAX) + " because stored value " + str(self.dpi[1]) + " is larger.") + self.dpi[1] = self.DPI_MAX + + dpi_func(self.dpi[0], self.dpi[1]) + + poll_rate_func = getattr(self, "setPollRate", None) + if poll_rate_func is not None: + # Constrain value in case the available values have changed, e.g. wired/wireless might different values available + if self.poll_rate not in self.POLL_RATES: + self.logger.warning("Constraining poll rate because stored value " + str(self.poll_rate) + " is not available.") + self.poll_rate = min(self.POLL_RATES, key=lambda x: abs(x - self.poll_rate)) + + poll_rate_func(self.poll_rate) + + def restore_brightness(self): + """ + Set the device to the current brightness/active state. + + This is used at launch time. + """ + for i in self.ZONES: + if self.zone[i]["present"]: + # load active state + if 'set_' + i + '_active' in self.METHODS: + active_func = getattr(self, "set" + self.capitalize_first_char(i) + "Active", None) + if active_func is not None: + active_func(self.zone[i]["active"]) + + # load brightness level + bright_func = None + if i == "backlight": + bright_func = getattr(self, "setBrightness", None) + elif 'set_' + i + '_brightness' in self.METHODS: + bright_func = getattr(self, "set" + self.capitalize_first_char(i) + "Brightness", None) + + if bright_func is not None: + bright_func(self.zone[i]["brightness"]) + + def disable_brightness(self): + """ + Set brightness to 0 and/or active state to false. + """ + for i in self.ZONES: + if self.zone[i]["present"]: + # set active state + if 'set_' + i + '_active' in self.METHODS: + active_func = getattr(self, "set" + self.capitalize_first_char(i) + "Active", None) + if active_func is not None: + active_func(False) + + # set brightness level + bright_func = None + if i == "backlight": + bright_func = getattr(self, "setBrightness", None) + elif 'set_' + i + '_brightness' in self.METHODS: + bright_func = getattr(self, "set" + self.capitalize_first_char(i) + "Brightness", None) + + if bright_func is not None: + bright_func(0) + + def restore_effect(self): + """ + Set the device to the current effect + + This is used at launch time and can be called by applications + that use custom matrix frames after they exit + """ + for i in self.ZONES: + if self.zone[i]["present"]: + # prepare the effect method name + # yes, we need to handle the backlight zone separately too. + # the backlight effect methods don't have a prefix. + if i == "backlight": + effect_func_name = 'set' + self.capitalize_first_char(self.zone[i]["effect"]) + else: + effect_func_name = 'set' + self.handle_underscores(self.capitalize_first_char(i)) + self.capitalize_first_char(self.zone[i]["effect"]) + + # find the effect method + effect_func = getattr(self, effect_func_name, None) + + # check if the effect method exists only if we didn't look for spectrum (because resetting to Spectrum when the effect is Spectrum is in vain) + if effect_func == None and not self.zone[i]["effect"] == "spectrum": + # not found. restoring to Spectrum + self.logger.info("%s: Invalid effect name %s; restoring to Spectrum.", self.__class__.__name__, effect_func_name) + self.zone[i]["effect"] = 'spectrum' + if i == "backlight": + effect_func_name = 'setSpectrum' + else: + effect_func_name = 'set' + self.capitalize_first_char(i) + 'Spectrum' + effect_func = getattr(self, effect_func_name, None) + + # we check again here because there is a possibility the device may not even have Spectrum + if effect_func is not None: + effect = self.zone[i]["effect"] + colors = self.zone[i]["colors"] + speed = self.zone[i]["speed"] + wave_dir = self.zone[i]["wave_dir"] + if self.get_num_arguments(effect_func) == 0: + effect_func() + elif self.get_num_arguments(effect_func) == 1: + # there are 2 effects which require 1 argument. + # these are: Starlight (Random) and Wave. + if effect == 'starlightRandom': + effect_func(speed) + elif effect == 'wave': + effect_func(wave_dir) + elif effect == 'wheel': + effect_func(wave_dir) + elif effect == 'rippleRandomColour': + # do nothing. this is handled in the ripple manager. + pass + else: + self.logger.error("%s: Effect requires 1 argument but don't know how to handle it!", self.__class__.__name__) + elif self.get_num_arguments(effect_func) == 3: + effect_func(colors[0], colors[1], colors[2]) + elif self.get_num_arguments(effect_func) == 4: + # starlight/reactive have different arguments. + if effect == 'starlightSingle' or effect == 'reactive': + effect_func(colors[0], colors[1], colors[2], speed) + elif effect == 'ripple': + # do nothing. this is handled in the ripple manager. + pass + else: + self.logger.error("%s: Effect requires 4 arguments but don't know how to handle it!", self.__class__.__name__) + elif self.get_num_arguments(effect_func) == 6: + effect_func(colors[0], colors[1], colors[2], colors[3], colors[4], colors[5]) + elif self.get_num_arguments(effect_func) == 7: + effect_func(colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], speed) + elif self.get_num_arguments(effect_func) == 9: + effect_func(colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], colors[6], colors[7], colors[8]) + else: + self.logger.error("%s: Couldn't detect effect argument count!", self.__class__.__name__) + + def set_persistence(self, zone, key, value): + """ + Set a device's current state for persisting across sessions. + + :param zone: Zone + :type zone: string + + :param key: Key + :type key: string + + :param value: Value + :type value: string + """ + if self._disable_persistence: + return + self.logger.debug("Set persistence (%s, %s, %s)", zone, key, value) + + self.persistence.status["changed"] = True + + if zone: + self.zone[zone][key] = value + else: + self.zone[key] = value + + def get_current_effect(self): + """ + Get the device's current effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_effect") + + return self.zone["backlight"]["effect"] + + def get_current_effect_colors(self): + """ + Get the device's current effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_effect_colors") + + return self.zone["backlight"]["colors"] + + def get_current_effect_speed(self): + """ + Get the device's current effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_effect_speed") + + return self.zone["backlight"]["speed"] + + def get_current_wave_dir(self): + """ + Get the device's current wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_wave_dir") + + return self.zone["backlight"]["wave_dir"] + + def get_current_logo_effect(self): + """ + Get the device's current logo effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_logo_effect") + + return self.zone["logo"]["effect"] + + def get_current_logo_effect_colors(self): + """ + Get the device's current logo effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_logo_effect_colors") + + return self.zone["logo"]["colors"] + + def get_current_logo_effect_speed(self): + """ + Get the device's current logo effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_logo_effect_speed") + + return self.zone["logo"]["speed"] + + def get_current_logo_wave_dir(self): + """ + Get the device's current logo wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_logo_wave_dir") + + return self.zone["logo"]["wave_dir"] + + def get_current_scroll_effect(self): + """ + Get the device's current scroll effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_scroll_effect") + + return self.zone["scroll"]["effect"] + + def get_current_scroll_effect_colors(self): + """ + Get the device's current scroll effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_scroll_effect_colors") + + return self.zone["scroll"]["colors"] + + def get_current_scroll_effect_speed(self): + """ + Get the device's current scroll effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_scroll_effect_speed") + + return self.zone["scroll"]["speed"] + + def get_current_scroll_wave_dir(self): + """ + Get the device's current scroll wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_scroll_wave_dir") + + return self.zone["scroll"]["wave_dir"] + + def get_current_left_effect(self): + """ + Get the device's current left effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_left_effect") + + return self.zone["left"]["effect"] + + def get_current_left_effect_colors(self): + """ + Get the device's current left effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_left_effect_colors") + + return self.zone["left"]["colors"] + + def get_current_left_effect_speed(self): + """ + Get the device's current left effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_left_effect_speed") + + return self.zone["left"]["speed"] + + def get_current_left_wave_dir(self): + """ + Get the device's current left wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_left_wave_dir") + + return self.zone["left"]["wave_dir"] + + def get_current_right_effect(self): + """ + Get the device's current right effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_right_effect") + + return self.zone["right"]["effect"] + + def get_current_right_effect_colors(self): + """ + Get the device's current right effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_right_effect_colors") + + return self.zone["right"]["colors"] + + def get_current_right_effect_speed(self): + """ + Get the device's current right effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_right_effect_speed") + + return self.zone["right"]["speed"] + + def get_current_right_wave_dir(self): + """ + Get the device's current right wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_right_wave_dir") + + return self.zone["right"]["wave_dir"] + + def get_current_charging_effect(self): + """ + Get the device's current charging effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_charging_effect") + + return self.zone["charging"]["effect"] + + def get_current_charging_effect_colors(self): + """ + Get the device's current charging effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_charging_effect_colors") + + return self.zone["charging"]["colors"] + + def get_current_charging_effect_speed(self): + """ + Get the device's current charging effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_charging_effect_speed") + + return self.zone["charging"]["speed"] + + def get_current_charging_wave_dir(self): + """ + Get the device's current charging wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_charging_wave_dir") + + return self.zone["charging"]["wave_dir"] + + def get_current_fast_charging_effect(self): + """ + Get the device's current fast_charging effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_fast_charging_effect") + + return self.zone["fast_charging"]["effect"] + + def get_current_fast_charging_effect_colors(self): + """ + Get the device's current fast_charging effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_fast_charging_effect_colors") + + return self.zone["fast_charging"]["colors"] + + def get_current_fast_charging_effect_speed(self): + """ + Get the device's current fast_charging effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_fast_charging_effect_speed") + + return self.zone["fast_charging"]["speed"] + + def get_current_fast_charging_wave_dir(self): + """ + Get the device's current fast_charging wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_fast_charging_wave_dir") + + return self.zone["fast_charging"]["wave_dir"] + + def get_current_fully_charged_effect(self): + """ + Get the device's current fully_charged effect + + :return: Effect + :rtype: string + """ + self.logger.debug("DBus call get_current_fully_charged_effect") + + return self.zone["fully_charged"]["effect"] + + def get_current_fully_charged_effect_colors(self): + """ + Get the device's current fully_charged effect's colors + + :return: 3 colors + :rtype: list of byte + """ + self.logger.debug("DBus call get_current_fully_charged_effect_colors") + + return self.zone["fully_charged"]["colors"] + + def get_current_fully_charged_effect_speed(self): + """ + Get the device's current fully_charged effect's speed + + :return: Speed + :rtype: int + """ + self.logger.debug("DBus call get_current_fully_charged_effect_speed") + + return self.zone["fully_charged"]["speed"] + + def get_current_fully_charged_wave_dir(self): + """ + Get the device's current fully_charged wave direction + + :return: Direction + :rtype: int + """ + self.logger.debug("DBus call get_current_fully_charged_wave_dir") + + return self.zone["fully_charged"]["wave_dir"] + + @property + def effect_sync(self): + """ + Propagate the obsever call upwards, used for syncing effects + + :return: Effects sync flag + :rtype: bool + """ + return self._effect_sync_propagate_up + + @effect_sync.setter + def effect_sync(self, value): + """ + Setting to true will propagate observer events upwards + + :param value: Effect sync + :type value: bool + """ + self._effect_sync_propagate_up = value + + @property + def disable_notify(self): + """ + Disable notifications flag + + :return: Flag + :rtype: bool + """ + return self._disable_notifications + + @disable_notify.setter + def disable_notify(self, value): + """ + Set the disable notifications flag + + :param value: Disable + :type value: bool + """ + self._disable_notifications = value + + @property + def disable_persistence(self): + """ + Disable persistence flag + + :return: Flag + :rtype: bool + """ + return self._disable_persistence + + @disable_persistence.setter + def disable_persistence(self, value): + """ + Set the disable persistence flag + + :param value: Disable + :type value: bool + """ + self._disable_persistence = value + + def get_driver_path(self, driver_filename): + """ + Get the path to a driver file + + :param driver_filename: Name of driver file + :type driver_filename: str + + :return: Full path to driver + :rtype: str + """ + return os.path.join(self._device_path, driver_filename) + + def get_serial(self): + """ + Get serial number for device + + :return: String of the serial number + :rtype: str + """ + # TODO raise exception if serial can't be got and handle during device add + if self._serial is None: + serial_path = os.path.join(self._device_path, 'device_serial') + count = 0 + serial = '' + while len(serial) == 0: + if count >= 5: + break + + try: + with open(serial_path, 'r') as f: + serial = f.read().strip() + except (PermissionError, OSError) as err: + self.logger.warning('getting serial: {0}'.format(err)) + serial = '' + except UnicodeDecodeError as err: + self.logger.warning('malformed serial: {0}'.format(err)) + serial = '' + + count += 1 + + if len(serial) == 0: + time.sleep(0.1) + self.logger.debug('getting serial: {0} count:{1}'.format(serial, count)) + + # Known bad serials: + # - just an empty string + # - "Default string" + # - "empty (NULL)" + # - "As printed in the D cover" + # - hex: 01 01 01 01 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 + if not re.fullmatch(r"[\dA-Z]+", serial): + self.logger.warning("Invalid serial number found, using a generated one.") + self.logger.warning("Original value: %s" % serial) + vid, pid = self.get_vid_pid() + idx = self._unknown_serial_counter.get((vid, pid), 0) + self._unknown_serial_counter[(vid, pid)] = idx + 1 + serial = "UNKNOWN_{0:04X}{1:04X}_{2:04d}".format(vid, pid, idx) + + self._serial = serial.replace(' ', '_') + + return self._serial + + def get_device_mode(self): + """ + Get device mode + + :return: String of device mode and arg separated by colon, e.g. 0:0 or 3:0 + :rtype: str + """ + device_mode_path = os.path.join(self._device_path, 'device_mode') + with open(device_mode_path, 'rb') as mode_file: + count = 0 + mode = mode_file.read().strip() + while len(mode) == 0: + if count >= 3: + break + mode = mode_file.read().strip() + + count += 1 + time.sleep(0.1) + + return "{0}:{1}".format(mode[0], mode[1]) + + def set_device_mode(self, mode_id, param): + """ + Set device mode + + :param mode_id: Device mode ID + :type mode_id: int + + :param param: Device mode parameter + :type param: int + """ + device_mode_path = os.path.join(self._device_path, 'device_mode') + with open(device_mode_path, 'wb') as mode_file: + + # Do some validation (even though its in the driver) + if mode_id not in (0, 3): + mode_id = 0 + if param != 0: + param = 0 + + mode_file.write(bytes([mode_id, param])) + + def _set_custom_effect(self): + """ + Set the device to use custom LED matrix + """ + # self.logger.debug("DBus call _set_custom_effect") + + driver_path = self.get_driver_path('matrix_effect_custom') + + payload = b'1' + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + def _set_key_row(self, payload): + """ + Set the RGB matrix on the device + + Byte array like + [1, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, + 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 255, 00, 255, 00, 00] + + First byte is row, on firefly its always 1, on keyboard its 0-5 + Then its 3byte groups of RGB + :param payload: Binary payload + :type payload: bytes + """ + # self.logger.debug("DBus call set_key_row") + + driver_path = self.get_driver_path('matrix_custom_frame') + + with open(driver_path, 'wb') as driver_file: + driver_file.write(payload) + + def _init_battery_manager(self): + """ + Initializes the BatteryManager using the provided name + """ + self._battery_manager = _BatteryManager(self, self._device_number, self.getDeviceName()) # pylint: disable=no-member + self._battery_manager.active = self.config.getboolean('Startup', 'battery_notifier', fallback=False) + self._battery_manager.frequency = self.config.getint('Startup', 'battery_notifier_freq', fallback=10 * 60) + self._battery_manager.percent = self.config.getint('Startup', 'battery_notifier_percent', fallback=33) + + def get_vid_pid(self): + """ + Get the usb VID PID + + :return: List of VID PID + :rtype: list of int + """ + result = [self.USB_VID, self.USB_PID] + return result + + def get_image_json(self): + # Deprecated API, but kept for backwards compatibility + return json.dumps({ + "top_img": self.get_device_image(), + "side_img": self.get_device_image(), + "perspective_img": self.get_device_image() + }) + + def get_device_image(self): + return self.DEVICE_IMAGE + + def load_methods(self): + """ + Load DBus methods + + Goes through the list in self.methods_internal and self.METHODS and loads each effect and adds it to DBus + """ + available_functions = {} + methods = dir(openrazer_daemon.dbus_services.dbus_methods) + for method in methods: + potential_function = getattr(openrazer_daemon.dbus_services.dbus_methods, method) + if isinstance(potential_function, types.FunctionType) and hasattr(potential_function, 'endpoint') and potential_function.endpoint: + available_functions[potential_function.__name__] = potential_function + + self.methods_internal.extend(self.METHODS) + for method_name in self.methods_internal: + try: + new_function = available_functions[method_name] + self.logger.debug("Adding %s.%s method to DBus", new_function.interface, new_function.name) + self.add_dbus_method(new_function.interface, new_function.name, new_function, new_function.in_sig, new_function.out_sig, new_function.byte_arrays) + except KeyError as e: + raise RuntimeError("Couldn't add method to DBus: " + str(e)) from None + + def suspend_device(self): + """ + Suspend device + """ + self.logger.info("Suspending %s", self.__class__.__name__) + self.disable_notify = True + self.disable_persistence = True + + self.disable_brightness() + self._suspend_device() + + self.disable_notify = False + self.disable_persistence = False + + def resume_device(self): + """ + Resume device + """ + self.logger.info("Resuming %s", self.__class__.__name__) + self.disable_notify = True + self.disable_persistence = True + + # Set device back to driver mode after e.g. suspend which resets the + # device to default device mode. + # NOTE: This is really the wrong place to put this, since this callback + # is for screensaver unlock, and not for 'wake up from suspend' or + # similar. Nevertheless for now this seems to be the best place for + # this and should resolve some issues with macro keys not working after + # suspend. + if self.DRIVER_MODE: + self.logger.info('Setting device back to "driver" mode.') + self.set_device_mode(0x03, 0x00) # Driver mode + + self.restore_brightness() + self._resume_device() + + self.disable_notify = False + self.disable_persistence = False + + def _suspend_device(self): + """ + Override to implement custom suspend behavior + """ + + def _resume_device(self): + """ + Override to implement custom resume behavior + """ + + def _close(self): + """ + To be overridden by any subclasses to do cleanup + """ + # Clear observer list + self._observer_list.clear() + + if self._battery_manager: + self._battery_manager.close() + + def close(self): + """ + Close any resources opened by subclasses + """ + if not self._is_closed: + # If this is a mouse, retrieve current DPI for local storage + # in case the user has changed the DPI on-the-fly + # (e.g. the DPI buttons) + if 'get_dpi_xy' in self.METHODS: + dpi_func = getattr(self, "getDPI", None) + if dpi_func is not None: + self.dpi = dpi_func() + + if self.DRIVER_MODE: + # Set back to device mode + try: + self.set_device_mode(0x00, 0x00) # Device mode + except FileNotFoundError: + pass + + self._close() + + self._is_closed = True + + def register_observer(self, observer): + """ + Observer design pattern, register + + :param observer: Observer + :type observer: object + """ + if observer not in self._observer_list: + self._observer_list.append(observer) + + def register_parent(self, parent): + """ + Register the parent as an observer to be optionally notified (sends to other devices) + + :param parent: Observer + :type parent: object + """ + self._parent = parent + + def remove_observer(self, observer): + """ + Obsever design pattern, remove + + :param observer: Observer + :type observer: object + """ + try: + self._observer_list.remove(observer) + except ValueError: + pass + + def notify_observers(self, msg): + """ + Notify observers with msg + + :param msg: Tuple with first element a string + :type msg: tuple + """ + if not self._disable_notifications: + self.logger.debug("Sending observer message: %s", str(msg)) + + if self._effect_sync_propagate_up and self._parent is not None: + self._parent.notify_parent(msg) + + for observer in self._observer_list: + observer.notify(msg) + + def notify(self, msg): + """ + Receive observer messages + + :param msg: Tuple with first element a string + :type msg: tuple + """ + self.logger.debug("Got observer message: %s", str(msg)) + + for observer in self._observer_list: + observer.notify(msg) + + @classmethod + def match(cls, device_id, dev_path): + """ + Match against the device ID + + :param device_id: Device ID like 0000:0000:0000.0000 + :type device_id: str + + :param dev_path: Device path. Normally '/sys/bus/hid/devices/0000:0000:0000.0000' + :type dev_path: str + + :return: True if its the correct device ID + :rtype: bool + """ + pattern = r'^[0-9A-F]{4}:' + '{0:04X}'.format(cls.USB_VID) + ':' + '{0:04X}'.format(cls.USB_PID) + r'\.[0-9A-F]{4}$' + + if re.match(pattern, device_id) is not None: + if 'device_type' in os.listdir(dev_path): + return True + + return False + + @staticmethod + def get_num_arguments(func): + """ + Get number of arguments in a function + + :param func: Function + :type func: callable + + :return: Number of arguments + :rtype: int + """ + func_sig = inspect.signature(func) + return len(func_sig.parameters) + + @staticmethod + def handle_underscores(string): + return re.sub(r'[_]+(?P[a-z])', lambda m: m.group('first').upper(), string) + + @staticmethod + def capitalize_first_char(string): + return string[0].upper() + string[1:] + + def __del__(self): + self.close() + + def __repr__(self): + return "{0}:{1}".format(self.__class__.__name__, self.serial) + + +class RazerDeviceBrightnessSuspend(RazerDevice): + """ + Class for devices that have get_brightness and set_brightness + """ + + def __init__(self, *args, **kwargs): + if 'additional_methods' in kwargs: + kwargs['additional_methods'].extend(['get_brightness', 'set_brightness']) + else: + kwargs['additional_methods'] = ['get_brightness', 'set_brightness'] + super().__init__(*args, **kwargs) diff --git a/openrazer/daemon/openrazer_daemon/hardware/headsets.py b/openrazer/daemon/openrazer_daemon/hardware/headsets.py new file mode 100644 index 00000000..ba4d9048 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/headsets.py @@ -0,0 +1,195 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Headsets class +""" +import re + +from openrazer_daemon.hardware.device_base import RazerDevice as __RazerDevice, RazerDeviceBrightnessSuspend as __RazerDeviceBrightnessSuspend +from openrazer_daemon.dbus_services.dbus_methods import kraken as _dbus_kraken, chroma_keyboard as _dbus_chroma + + +class RazerKraken71(__RazerDevice): + """ + Class for the Razer Kraken 7.1 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Kraken_7\.1_000000000000-event-if03') + + USB_VID = 0x1532 + USB_PID = 0x0501 + METHODS = ['get_device_type_headset', + 'set_static_effect', 'set_none_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/229/229_kraken_71.png" + + def _suspend_device(self): + self.suspend_args.clear() + self.suspend_args['effect'] = self.zone["backlight"]["effect"] + + _dbus_chroma.set_none_effect(self) + + def _resume_device(self): + effect = self.suspend_args.get('effect', '') + if effect == 'static': # Static on classic is only 1 colour + _dbus_chroma.set_static_effect(self, 0x00, 0x00, 0x00) + + +class RazerKraken71Alternate(RazerKraken71): + """ + Class for the Razer Kraken 7.1 (Alternate) + """ + USB_PID = 0x0506 + + +class RazerKraken71Chroma(__RazerDevice): + """ + Class for the Razer Kraken 7.1 Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Kraken_7\.1_Chroma-event-if03') + + USB_VID = 0x1532 + USB_PID = 0x0504 + METHODS = ['get_device_type_headset', + 'set_static_effect', 'set_spectrum_effect', 'set_none_effect', 'set_breath_single_effect', + 'set_custom_kraken'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/280/280_kraken_71_chroma.png" + + def _suspend_device(self): + self.suspend_args.clear() + self.suspend_args['effect'] = self.zone["backlight"]["effect"] + self.suspend_args['args'] = self.zone["backlight"]["colors"][0:3] + + _dbus_chroma.set_none_effect(self) + + def _resume_device(self): + effect = self.suspend_args.get('effect', '') + args = self.suspend_args.get('args', []) + + if effect == 'spectrum': + _dbus_chroma.set_spectrum_effect(self) + elif effect == 'static': + _dbus_chroma.set_static_effect(self, *args) + elif effect == 'breathSingle': + _dbus_chroma.set_breath_single_effect(self, *args) + + +class RazerKraken71V2(__RazerDevice): + """ + Class for the Razer Kraken 7.1 V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Kraken_7\.1_V2_0+-event-if03') + + USB_VID = 0x1532 + USB_PID = 0x0510 + METHODS = ['get_device_type_headset', + 'set_static_effect', 'set_spectrum_effect', 'set_none_effect', 'set_breath_single_effect', 'set_breath_dual_effect', 'set_breath_triple_effect', + 'set_custom_kraken'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/729/729_kraken_71_v2.png" + + def _suspend_device(self): + self.suspend_args.clear() + self.suspend_args['effect'] = self.zone["backlight"]["effect"] + if self.suspend_args['effect'] == "breathDual": + self.suspend_args['args'] = self.zone["backlight"]["colors"][0:6] + elif self.suspend_args['effect'] == "breathTriple": + self.suspend_args['args'] = self.zone["backlight"]["colors"][0:9] + else: + self.suspend_args['args'] = self.zone["backlight"]["colors"][0:3] + + _dbus_chroma.set_none_effect(self) + + def _resume_device(self): + effect = self.suspend_args.get('effect', '') + args = self.suspend_args.get('args', []) + + if effect == 'spectrum': + _dbus_chroma.set_spectrum_effect(self) + elif effect == 'static': + _dbus_chroma.set_static_effect(self, *args) + elif effect == 'breathSingle': + _dbus_chroma.set_breath_single_effect(self, *args) + elif effect == 'breathDual': + _dbus_chroma.set_breath_dual_effect(self, *args) + elif effect == 'breathTriple': + _dbus_chroma.set_breath_triple_effect(self, *args) + + +class RazerKrakenUltimate(__RazerDevice): + """ + Class for the Razer Kraken Ultimate + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Kraken_Ultimate_0+-event-if03') + + USB_VID = 0x1532 + USB_PID = 0x0527 + METHODS = ['get_device_type_headset', + 'set_static_effect', 'set_spectrum_effect', 'set_none_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_breath_triple_effect', + 'set_custom_kraken'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1603/rzr_kraken_ultimate_render01_2019_resized.png" + + def _suspend_device(self): + self.suspend_args.clear() + self.suspend_args['effect'] = self.zone["backlight"]["effect"] + if self.suspend_args['effect'] == "breathDual": + self.suspend_args['args'] = self.zone["backlight"]["colors"][0:6] + elif self.suspend_args['effect'] == "breathTriple": + self.suspend_args['args'] = self.zone["backlight"]["colors"][0:9] + else: + self.suspend_args['args'] = self.zone["backlight"]["colors"][0:3] + + _dbus_chroma.set_none_effect(self) + + def _resume_device(self): + effect = self.suspend_args.get('effect', '') + args = self.suspend_args.get('args', []) + + if effect == 'spectrum': + _dbus_chroma.set_spectrum_effect(self) + elif effect == 'static': + _dbus_chroma.set_static_effect(self, *args) + elif effect == 'breathSingle': + _dbus_chroma.set_breath_single_effect(self, *args) + elif effect == 'breathDual': + _dbus_chroma.set_breath_dual_effect(self, *args) + elif effect == 'breathTriple': + _dbus_chroma.set_breath_triple_effect(self, *args) + + +class RazerKrakenKittyEdition(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Kraken Kitty Edition + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Kraken_Kitty_Chroma_Control-event-if00') + + USB_VID = 0x1532 + USB_PID = 0x0F19 + METHODS = ['get_device_type_headset', + 'set_none_effect', 'set_static_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_starlight_random_effect', 'set_starlight_single_effect', + 'set_starlight_dual_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_custom_effect', 'set_key_row', + 'set_brightness', 'get_brightness'] + HAS_MATRIX = True + MATRIX_DIMS = [1, 4] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/pnx.assets/1c503aa176bc82d999299aba0d6c7d2c/kraken-kitty-quartz.png" + + +class RazerKrakenKittyV2(__RazerDevice): + """ + Class for the Razer Kraken Kitty V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Kraken_Kitty_V2_00000000-event-if03') + + USB_VID = 0x1532 + USB_PID = 0x0560 + METHODS = ['get_device_type_headset', + 'set_static_effect', 'set_spectrum_effect', 'set_none_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_breath_triple_effect', + 'set_custom_kraken'] + + DEVICE_IMAGE = "https://medias-p1.phoenix.razer.com/sys-master-phoenix-images-container/hcc/h6b/9631977570334/kraken-kitty-v2-quartz-500x500.png" diff --git a/openrazer/daemon/openrazer_daemon/hardware/keyboards.py b/openrazer/daemon/openrazer_daemon/hardware/keyboards.py new file mode 100644 index 00000000..5f83a00f --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/keyboards.py @@ -0,0 +1,2165 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Keyboards class +""" +import re + +from openrazer_daemon.hardware.device_base import RazerDeviceBrightnessSuspend as _RazerDeviceBrightnessSuspend +from openrazer_daemon.misc.key_event_management import KeyboardKeyManager as _KeyboardKeyManager, GamepadKeyManager as _GamepadKeyManager, OrbweaverKeyManager as _OrbweaverKeyManager +from openrazer_daemon.misc.ripple_effect import RippleManager as _RippleManager + + +class _MacroKeyboard(_RazerDeviceBrightnessSuspend): + """ + Keyboard class + + Has macro functionality and brightness based suspend + """ + DRIVER_MODE = True + + def __init__(self, *args, **kwargs): + if 'additional_methods' in kwargs: + kwargs['additional_methods'].extend(['get_keyboard_layout']) + else: + kwargs['additional_methods'] = ['get_keyboard_layout'] + super().__init__(*args, **kwargs) + # Methods are loaded into DBus by this point + + self.key_manager = _KeyboardKeyManager(self._device_number, self.event_files, self, use_epoll=True, testing=self._testing) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + self.key_manager.close() + + +class _RippleKeyboard(_MacroKeyboard): + """ + Keyboard class + + Inherits _MacroKeyboard and has a ripple manager + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if not self.HAS_MATRIX: + # You can use _MacroKeyboard instead if the keyboard doesn't support matrix + raise RuntimeError("Cannot use RippleKeyboard without matrix capabilities") + + self.ripple_manager = _RippleManager(self, self._device_number) + + # we need to set the effect to ripple (if needed) after the ripple manager has started + # otherwise it doesn't work + if self.zone["backlight"]["effect"] == "ripple" or self.zone["backlight"]["effect"] == "rippleRandomColour": + effect_func_name = 'set' + self.capitalize_first_char(self.zone["backlight"]["effect"]) + effect_func = getattr(self, effect_func_name, None) + + if effect_func is not None: + if effect_func_name == 'setRipple': + effect_func(self.zone["backlight"]["colors"][0], self.zone["backlight"]["colors"][1], self.zone["backlight"]["colors"][2], self.ripple_manager._ripple_thread._refresh_rate) + elif effect_func_name == 'setRippleRandomColour': + effect_func(self.ripple_manager._ripple_thread._refresh_rate) + + def _close(self): + super()._close() + + self.ripple_manager.close() + + +class RazerNostromo(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Nostromo + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Nostromo-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0111 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keypad', 'keypad_get_profile_led_red', 'keypad_set_profile_led_red', 'keypad_get_profile_led_green', 'keypad_set_profile_led_green', 'keypad_get_profile_led_blue', 'keypad_set_profile_led_blue', + 'get_macros', 'delete_macro', 'add_macro', + + # ? + 'keypad_get_mode_modifier', 'keypad_set_mode_modifier'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/564/564_tartarus_classic.png" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Methods are loaded into DBus by this point + + # self.key_manager = _GamepadKeyManager(self._device_number, self.event_files, self, testing=self._testing) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerTartarus(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Tartarus + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Tartarus(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0201 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keypad', + 'set_static_effect', 'bw_set_pulsate', 'keypad_get_profile_led_red', 'keypad_set_profile_led_red', 'keypad_get_profile_led_green', + 'keypad_set_profile_led_green', 'keypad_get_profile_led_blue', 'keypad_set_profile_led_blue', 'get_macros', 'delete_macro', 'add_macro', 'keypad_get_mode_modifier', 'keypad_set_mode_modifier'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/228/228_tartarus.png" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Methods are loaded into DBus by this point + + # self.key_manager = _GamepadKeyManager(self._device_number, self.event_files, self, testing=self._testing) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerTartarusChroma(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Tartarus Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Tartarus_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0208 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keypad', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_none_effect', 'set_static_effect', 'set_spectrum_effect', 'keypad_get_profile_led_red', 'keypad_set_profile_led_red', 'keypad_get_profile_led_green', + 'keypad_set_profile_led_green', 'keypad_get_profile_led_blue', 'keypad_set_profile_led_blue', 'get_macros', 'delete_macro', 'add_macro', 'keypad_get_mode_modifier', 'keypad_set_mode_modifier'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/598/598_tartarus_chroma.png" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Methods are loaded into DBus by this point + + # self.key_manager = _GamepadKeyManager(self._device_number, self.event_files, self, testing=self._testing) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerTartarusV2(_RippleKeyboard): + """ + Class for Razer Tartarus V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Tartarus_V2(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x022B + HAS_MATRIX = True + DEDICATED_MACRO_KEYS = True + MATRIX_DIMS = [4, 6] + + METHODS = ['get_device_type_keypad', + 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_key_row', + 'set_reactive_effect', + 'set_none_effect', + 'set_custom_effect', + 'set_wave_effect', + 'set_static_effect', + 'set_spectrum_effect', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'keypad_get_profile_led_red', 'keypad_set_profile_led_red', + 'keypad_get_profile_led_green', 'keypad_set_profile_led_green', + 'keypad_get_profile_led_blue', 'keypad_set_profile_led_blue', + 'get_macro_mode', 'set_macro_mode', 'get_macro_effect', 'set_macro_effect', + 'get_macros', 'delete_macro', 'add_macro', + 'set_ripple_effect', 'set_ripple_effect_random_colour', + 'get_game_mode', 'set_game_mode', + 'keypad_get_mode_modifier', 'keypad_set_mode_modifier'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1255/1255_tartarus_v2.png" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerOrbweaver(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Orbweaver + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Orbweaver(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0113 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keypad', + 'keypad_get_profile_led_red', 'keypad_set_profile_led_red', 'keypad_get_profile_led_green', 'keypad_set_profile_led_green', 'keypad_get_profile_led_blue', 'keypad_set_profile_led_blue', + 'get_macros', 'delete_macro', 'add_macro', 'keypad_get_mode_modifier', 'keypad_set_mode_modifier', + 'set_none_effect', 'bw_set_pulsate', 'bw_set_static'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/56/56_orbweaver.png" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Methods are loaded into DBus by this point + + # self.key_manager = _OrbweaverKeyManager(self._device_number, self.event_files, self, testing=self._testing) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerOrbweaverChroma(_RippleKeyboard): + """ + Class for the Razer Orbweaver Chroma + """ + + EVENT_FILE_REGEX = re.compile(r'.*Razer_Orbweaver_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0207 + DEDICATED_MACRO_KEYS = True + HAS_MATRIX = True + MATRIX_DIMS = [5, 22] + METHODS = ['get_device_type_keypad', + 'set_key_row', + 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_none_effect', 'set_static_effect', 'set_spectrum_effect', 'set_wave_effect', 'set_custom_effect', + 'keypad_get_profile_led_red', 'keypad_set_profile_led_red', + 'keypad_get_profile_led_green', 'keypad_set_profile_led_green', + 'keypad_get_profile_led_blue', 'keypad_set_profile_led_blue', + 'get_macros', 'delete_macro', 'add_macro', + 'keypad_get_mode_modifier', 'keypad_set_mode_modifier', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/607/607_orbweaver_chroma.png" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Methods are loaded into DBus by this point + + # self.key_manager = _OrbweaverKeyManager(self._device_number, self.event_files, self, testing=self._testing) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerBlackWidowUltimate2012(_MacroKeyboard): + """ + Class for the Razer BlackWidow Ultimate 2012 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_BlackWidow_Ultimate_2012(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x010D + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keyboard', 'get_game_mode', 'set_game_mode', 'set_macro_mode', 'get_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'bw_set_pulsate', 'bw_set_static', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/563/563_blackwidow_ultimate_classic.png" + + +class RazerBlackWidowStealth(_MacroKeyboard): + """ + Class for the Razer BlackWidow (Classic) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_BlackWidow(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x011B + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keyboard', 'get_game_mode', 'set_game_mode', 'set_macro_mode', 'get_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'bw_set_pulsate', 'bw_set_static', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/17559/razer-blackwidow-gallery-01.png" + + +class RazerBlackWidowStealthEdition(_MacroKeyboard): + """ + Class for the Razer BlackWidow Stealth Edition + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_BlackWidow(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x010E + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keyboard', 'get_game_mode', 'set_game_mode', 'set_macro_mode', 'get_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'bw_set_pulsate', 'bw_set_static', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/17559/razer-blackwidow-gallery-01.png" + + +class RazerBlackWidowUltimate2013(_MacroKeyboard): + """ + Class for the Razer BlackWidow Ultimate 2013 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_BlackWidow_Ultimate(_2013)?(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x011A + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keyboard', 'get_game_mode', 'set_game_mode', 'set_macro_mode', 'get_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'bw_set_pulsate', 'bw_set_static', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/245/438_blackwidow_ultimate_2014.png" + + +class RazerBlackWidowTournamentEdition2014(_MacroKeyboard): + """ + Class for the Razer BlackWidow Tournament Edition 2014 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_BlackWidow_Tournament_Edition(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x011C + METHODS = ['get_device_type_keyboard', 'get_game_mode', 'set_game_mode', 'set_macro_mode', 'get_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'bw_set_pulsate', 'bw_set_static', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/17564/razer-blackwidow-te-stealth-hero-01.png" + + +class RazerBlackWidowV3ProWired(_RippleKeyboard): + """ + Class for the Razer BlackWidow V3 Pro Wired + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_BlackWidow_V3_Pro(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x025A + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', + # Battery + 'set_charge_effect', 'set_charge_colour', 'get_battery', 'is_charging', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/3809-1-EN-v1.png" + + +class RazerBlackWidowV3ProWireless(RazerBlackWidowV3ProWired): + """ + Class for the Razer BlackWidow V3 Pro 2.4 Ghz Wireless + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_BlackWidow_V3_Pro(_\d+)?(-if01)?-event-kbd') + + USB_PID = 0x025C + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + # TODO: + # Ripple works with this keyboard when plugged as wired but failed + # to get it to work in wireless mode. + # 'set_ripple_effect', 'set_ripple_effect_random_colour', + 'set_charge_effect', 'set_charge_colour', 'get_battery', 'is_charging', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/3809-1-EN-v1.png" + + +class RazerBlackWidowChroma(_RippleKeyboard): + """ + Class for the Razer BlackWidow Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0203 + HAS_MATRIX = True + DEDICATED_MACRO_KEYS = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/279/279_blackwidow_chroma.png" + + +class RazerBlackWidowChromaV2(_RippleKeyboard): + """ + Class for the BlackWidow Chroma V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_Chroma_V2(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0221 + HAS_MATRIX = True + DEDICATED_MACRO_KEYS = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1179/1179_blackwidow_chroma_v2_alt.png" + + +class RazerBlackWidowChromaTournamentEdition(_RippleKeyboard): + """ + Class for the Razer BlackWidow Tournament Edition Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_Tournament_Edition_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0209 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macros', 'delete_macro', 'add_macro', + 'get_macro_mode', 'set_macro_mode', 'get_macro_effect', 'set_macro_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/571/571_blackwidow_tournament_edition_chroma.png" + + +class RazerBlackWidowXChroma(_RippleKeyboard): + """ + Class for the Razer BlackWidow X Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_X_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0216 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/716/716_blackwidow_x_chroma.png" + + +class RazerHuntsmanV2Tenkeyless(_RippleKeyboard): + """ + Class for the Razer Huntsman V2 Tenkeyless + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Huntsman_V2_Tenkeyless(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x026B + HAS_MATRIX = True + MATRIX_DIMS = [6, 18] + POLL_RATES = [125, 250, 500, 1000, 2000, 4000, 8000] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', 'get_keyswitch_optimization', 'set_keyswitch_optimization', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/5638/5638-1-en-v1.png" + + +class RazerHuntsmanV2(_RippleKeyboard): + """ + Class for the Razer Huntsman V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Huntsman_V2(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x026C + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + POLL_RATES = [125, 250, 500, 1000, 2000, 4000, 8000] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', 'get_keyswitch_optimization', 'set_keyswitch_optimization', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/5642/5642-1-en-v1.png" + + +# TODO Should become _RippleKeyboard once kernel support for driver mode is implemented +class RazerHuntsmanV2Analog(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Huntsman V2 Analog + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Huntsman_V2_Analog(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0266 + HAS_MATRIX = True + MATRIX_DIMS = [8, 22] + # TODO Remove get_keyboard_layout once not _RazerDeviceBrightnessSuspend anymore + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'get_macro_mode', 'set_macro_mode', 'get_macro_effect', 'set_macro_effect', 'get_game_mode', 'set_game_mode', + 'set_custom_effect', 'set_key_row', 'get_keyboard_layout'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/4023-1-EN-v1.png" + + +class RazerHuntsmanV3Pro(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Huntsman V3 Pro + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Huntsman_V3_Pro(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02A6 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + # TODO Remove get_keyboard_layout once not _RazerDeviceBrightnessSuspend anymore + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'get_macro_mode', 'set_macro_mode', 'get_macro_effect', 'set_macro_effect', + 'get_game_mode', 'set_game_mode', 'set_custom_effect', 'set_key_row', 'get_keyboard_layout'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13671/13671-1-en-v2.png" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.key_manager = _KeyboardKeyManager(self._device_number, self.event_files, self, use_epoll=True, testing=self._testing) + + def _close(self): + """ + Close the key manager + """ + super()._close() + self.key_manager.close() + + +# TODO Should become _RippleKeyboard once kernel support for driver mode is implemented +class RazerHuntsmanMiniAnalog(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Huntsman Mini Analog + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Huntsman_Mini_Analog(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0282 + HAS_MATRIX = True + MATRIX_DIMS = [5, 15] + # TODO Remove get_keyboard_layout once not _RazerDeviceBrightnessSuspend anymore + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'get_macro_mode', 'set_macro_mode', 'get_macro_effect', 'set_macro_effect', 'get_game_mode', 'set_game_mode', + 'set_custom_effect', 'set_key_row', 'get_keyboard_layout'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1689/1689-huntsmanmini.png" + + +class RazerBlackWidowXTournamentEditionChroma(_RippleKeyboard): + """ + Class for the Razer BlackWidow X Tournament Edition Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_X_Tournament_Edition_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x021A + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/717/717_blackwidow_x_tournament_edition_chroma.png" + + +class RazerBladeStealth(_RippleKeyboard): + """ + Class for the Razer Blade Stealth + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0205 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/667/667_blade_stealth_2016_6500u.png" + + +class RazerBladeStealthLate2016(_RippleKeyboard): + """ + Class for the Razer Blade Stealth (Late 2016) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0220 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/667/667_blade_stealth_2016_6500u.png" + + +class RazerBladeProLate2016(_MacroKeyboard): + """ + Class for the Razer Blade Pro (Late 2016) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Pro(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0210 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_starlight_random_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/736/736_blade_pro_2016.png" + + +class RazerBladeLate2016(_RippleKeyboard): + """ + Class for the Razer Blade (Late 2016) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0224 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_starlight_random_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/736/736_blade_pro_2016.png" + + +class RazerBladeQHD(_RippleKeyboard): + """ + Class for the Razer Blade (QHD) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x020F + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', + 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_starlight_random_effect', + + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/736/736_blade_pro_2016.png" + + +class RazerBlackWidowUltimate2016(_RippleKeyboard): + """ + Class for the Razer BlackWidow Ultimate 2016 + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_Ultimate_2016(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0214 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', 'set_starlight_random_effect', + + 'set_ripple_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/616/616_blackwidow_ultimate_2016.png" + + +class RazerBlackWidowXUltimate(_RippleKeyboard): + """ + Class for the Razer BlackWidow X Ultimate + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_X_Ultimate(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0217 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', 'set_starlight_random_effect', + + 'set_ripple_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/718/718_blackwidow_x_ultimate.png" + + +class RazerOrnataChroma(_RippleKeyboard): + """ + Class for the Razer Ornata Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*Ornata_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x021E + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/727/727_ornata_chroma.png" + + +class RazerOrnataV2(_RippleKeyboard): + """ + Class for the Razer Ornata V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Ornata_V2(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x025D + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1672/ornata-v2.png" + + +class RazerOrnataV3(_RippleKeyboard): + """ + Class for the Razer Ornata V3 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Ornata_V3(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02A1 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 10] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6075-1-en-v1.png" + + +class RazerOrnataV3_Alternate(RazerOrnataV3): + """ + Class for the Razer Ornata V3 (Alternate) + """ + USB_PID = 0x028F + + +class RazerOrnataV3X(_MacroKeyboard): + """ + Class for the Razer Ornata V3 X + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Ornata_V3_X(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0294 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6071-1-en-v1.png" + + +class RazerOrnataV3X_Alternate(RazerOrnataV3X): + """ + Class for the Razer Ornata V3 X (Alternate) + """ + USB_PID = 0x02A2 + + +class RazerOrnataV3Tenkeyless(_RippleKeyboard): + """ + Class for the Razer Ornata V3 Tenkeyless + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Ornata_V3_Tenkeyless(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02A3 + HAS_MATRIX = True + MATRIX_DIMS = [1, 8] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', 'set_ripple_effect', + 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13038/13038-1-en-v1.png" + + +class RazerBlackWidowV4_75PCT(_RippleKeyboard): + """ + Class for the Razer BlackWidow V4 75% + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_BlackWidow_V4_75_(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02A5 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [6, 16] + POLL_RATES = [125, 250, 500, 1000, 2000, 4000, 8000] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_wheel_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13256/13256-1-en-v2.png" + + +class RazerHuntsmanElite(_RippleKeyboard): + """ + Class for the Razer Huntsman Elite + """ + EVENT_FILE_REGEX = re.compile(r'.*Huntsman_Elite(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0226 + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [9, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1361/1361_huntsman_elite.png" + + +class RazerHuntsmanTournamentEdition(_RippleKeyboard): + """ + Class for the Razer Huntsman Tournament Edition + """ + EVENT_FILE_REGEX = re.compile(r'.*Huntsman_Tournament_Edition_00000000001A(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0243 + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 18] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1537/1537_huntsman_te.png" + + +class RazerBlackWidowElite(_RippleKeyboard): + """ + Class for the Razer BlackWidow Elite + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_Elite(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0228 + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1398/1398_blackwidowelite.png" + + +class RazerHuntsman(_RippleKeyboard): + """ + Class for the Razer Huntsman + """ + EVENT_FILE_REGEX = re.compile(r'.*Huntsman(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0227 + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1360/1360_huntsman-3.png" + + +class RazerBlackWidowV3(_RippleKeyboard): + """ + Class for the Razer BlackWidow V3 + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_V3(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x024E + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/3827-1-EN-v1.png" + + +class RazerBlackWidowV3TK(_RippleKeyboard): + """ + Class for the Razer BlackWidow V3 TK + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_V3_Tenkeyless(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0A24 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [6, 18] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1709/1709-blackwidow-v3-tkl.png" + + +class RazerBlackWidowV3MiniHyperspeed(_RippleKeyboard): + """ + Class for the Razer BlackWidow V3 Mini Hyperspeed + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_V3_Mini_000000000000(-if01)?-event-mouse') + + USB_VID = 0x1532 + USB_PID = 0x0258 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [5, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_battery', 'is_charging'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1777/500x500-blackwidowv3mini.png" + + +class RazerBlackWidowV3MiniHyperspeedWireless(RazerBlackWidowV3MiniHyperspeed): + """ + Class for the Razer BlackWidow V3 Mini Hyperspeed (Wireless) + """ + USB_PID = 0x0271 + + +class RazerCynosaChroma(_RippleKeyboard): + """ + Class for the Razer Cynosa Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*Cynosa_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x022A + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1256/1256_cynosa_chroma.png" + + +class RazerCynosaChromaPro(_RippleKeyboard): + """ + Class for the Razer Cynosa Chroma Pro + """ + EVENT_FILE_REGEX = re.compile(r'.*Cynosa_Chroma_Pro(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x022C + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1257/1257_cynosa_chroma_pro_alt.png" + + +class RazerCynosaV2(_RippleKeyboard): + """ + Class for the Razer Cynosa V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Cynosa_V2(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x025E + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1694/1694-2.png" + + +class RazerCynosaLite(_MacroKeyboard): + """ + Class for the Razer Cynosa Lite + """ + EVENT_FILE_REGEX = re.compile(r'.*Cynosa_Lite(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x023F + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/og-image/cynosa-lite-OGimage.jpg" + + +class RazerBlackWidowLite(_MacroKeyboard): + """ + Class for the Razer BlackWidow Lite + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_Lite(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0235 + METHODS = ['get_device_type_keyboard', 'set_static_effect', + 'set_none_effect', 'set_breath_single_effect', + 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1456/1456_blackwidowlite_-_2.png" + + +class RazerBlackWidow2019(_RippleKeyboard): + """ + Class for the Razer BlackWidow 2019 + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0241 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1501/1501-blackwidow2019.png" + + +class RazerBlackWidowEssential(_RippleKeyboard): + """ + Class for the Razer BlackWidow Essential + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_BlackWidow_Essential(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0237 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_none_effect', + 'set_spectrum_effect', 'set_wave_effect', 'set_reactive_effect', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_breath_single_effect', 'set_key_row', 'set_custom_effect', 'get_game_mode', + 'set_game_mode', 'get_macro_mode', 'set_macro_mode', 'get_macro_effect', + 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1501/1501-blackwidow2019.png" + + +class RazerOrnata(_RippleKeyboard): + """ + Class for the Razer Ornata + """ + EVENT_FILE_REGEX = re.compile(r'.*Ornata(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x021F + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_single_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', 'set_breath_single_effect', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/726/726_ornata.png" + + +class RazerAnansi(_MacroKeyboard): + """ + Class for the Razer Anansi + """ + EVENT_FILE_REGEX = re.compile(r'.*Anansi(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x010F + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_keyboard', + 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', 'get_macro_effect', + 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', 'set_static_effect', + 'set_spectrum_effect', 'set_none_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/54/54_anansi.png" + + +class RazerDeathStalkerExpert(_MacroKeyboard): + """ + Class for the Razer DeathStalker Expert + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_DeathStalker(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0202 + METHODS = ['get_device_type_keyboard', 'get_game_mode', 'set_game_mode', 'set_macro_mode', 'get_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'bw_set_pulsate', 'bw_set_static', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/49/49_razer_deathstalker.png" + + +class RazerDeathStalkerEssential(_MacroKeyboard): + """ + Class for the Razer DeathStalker/DeathStalker Essential + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_DeathStalker(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0118 + METHODS = ['get_device_type_keyboard', 'get_game_mode', 'set_game_mode', 'set_macro_mode', 'get_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'bw_set_pulsate', 'bw_set_static', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/49/49_razer_deathstalker.png" + + +class RazerDeathStalkerChroma(_RippleKeyboard): + """ + Class for the Razer DeathStalker Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*DeathStalker_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0204 + HAS_MATRIX = True + DEDICATED_MACRO_KEYS = True + MATRIX_DIMS = [1, 12] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/665/665_deathstalker_chroma.png" + + +class RazerDeathStalkerV2(_RippleKeyboard): + """ + Class for the Razer DeathStalker V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*DeathStalker_V2(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0295 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6118/6118-1-en-v1.png" + + +class RazerDeathStalkerV2ProWired(_RippleKeyboard): + """ + Class for the Razer DeathStalker V2 Pro (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*DSV2_Pro_000000000000-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0292 + HAS_MATRIX = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', + # Battery + 'get_battery', 'is_charging'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6118/6118-1-en-v1.png" + + +class RazerDeathStalkerV2ProWireless(RazerDeathStalkerV2ProWired): + """ + Class for the Razer DeathStalker V2 Pro (Wireless) + """ + USB_PID = 0x0290 + + +class RazerDeathStalkerV2ProTKLWired(_RippleKeyboard): + """ + Class for the Razer DeathStalker V2 Pro TKL (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*DSV2Pro_TKL-if01-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0298 + HAS_MATRIX = True + MATRIX_DIMS = [6, 17] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', + # Battery + 'get_battery', 'is_charging'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6117/6117-1-en-v1.png" + + +class RazerDeathStalkerV2ProTKLWireless(RazerDeathStalkerV2ProTKLWired): + """ + Class for the Razer DeathStalker V2 Pro TKL (Wireless) + """ + USB_PID = 0x0296 + EVENT_FILE_REGEX = re.compile(r'.*DSV2Pro_TKL_000000000000-if01-event-mouse') + + +class RazerBlackWidowChromaOverwatch(_RippleKeyboard): + """ + Class for the Razer BlackWidow Chroma (Overwatch) + """ + EVENT_FILE_REGEX = re.compile(r'.*BlackWidow_Chroma(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0211 + HAS_MATRIX = True + DEDICATED_MACRO_KEYS = True + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/23326/overwatch-razer-gallery-5.png" + + +class RazerBladeStealthMid2017(_RippleKeyboard): + """ + Class for the Razer Blade Stealth (Mid 2017) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x022D + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1213/1213_blade_stealth_2017_7500u.png" + + +class RazerBladePro2017(_RippleKeyboard): + """ + Class for the Razer Blade Pro (2017) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Pro(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0225 + HAS_MATRIX = True + MATRIX_DIMS = [6, 25] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_starlight_random_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1200/1200_blade_pro_2017.png" + + +class RazerBladePro2017FullHD(_RippleKeyboard): + """ + Class for the Razer Blade Pro FullHD (2017) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_ProFullHD(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x022F + HAS_MATRIX = True + MATRIX_DIMS = [6, 25] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_starlight_random_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1200/1200_blade_pro_2017.png" + + +class RazerBladeStealthLate2017(_RippleKeyboard): + """ + Class for the Razer Blade Stealth (Late 2017) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0232 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1213/1213_blade_stealth_2017_7500u.png" + + +class RazerBlade2018(_RippleKeyboard): + """ + Class for the Razer Blade 15 (2018) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0233 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', 'set_starlight_random_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour', 'get_logo_active', 'set_logo_active'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1418/1418_blade_2018__base.png" + + +class RazerBlade2018Mercury(_RippleKeyboard): + """ + Class for the Razer Blade 15 (2018) Mercury + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0240 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', 'set_starlight_random_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1552/1552-blade-stealth-mercury-white.png" + + +class RazerBlade2018Base(_MacroKeyboard): + """ + Class for the Razer Blade 15 (2018) Base Model + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x023B + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1418/1418_blade_2018__base.png" + + +class RazerBladeStealth2019(_MacroKeyboard): + """ + Class for the Razer Blade Stealth (2019) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0239 + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1475/1475_bladestealth13(2019).png" + + +class RazerBladeStealthLate2019(_MacroKeyboard): + """ + Class for the Razer Blade Stealth (Late 2019) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x024A + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/blade-stealth-13/shop/stealth-l2p-1.jpg" + + +class RazerBladeStealthEarly2020(_MacroKeyboard): + """ + Class for the Razer Blade Stealth (Early 2020) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0252 + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/blade-stealth-13/shop/sl25p-fhd-4.jpg" + + +class RazerBladeStealthLate2020(_MacroKeyboard): + """ + Class for the Razer Blade Stealth (Late 2020) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade_Stealth(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0259 + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/blade-stealth-13/shop/sl25p-fhd-4.jpg" + + +class RazerBook2020(_MacroKeyboard): + """ + Class for the Razer Book (2020) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x026A + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1743/razerbook132020.png" + + +class RazerBlade2019Adv(_RippleKeyboard): + """ + Class for the Razer Blade 15 (2019) Advanced + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x023A + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1482/blade15.png" + + +class RazerBladeMid2019Mercury(_RippleKeyboard): + """ + Class for the Razer Blade 15 (Mid 2019) Mercury + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0245 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/blade-15/shop/blade15-mercury-1.jpg" + + +class RazerBlade2019Base(_MacroKeyboard): + """ + Class for the Razer Blade 15 (Mid 2019) Base Model + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0246 + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1518/1518_blade15_mid2019-base.png" + + +class RazerBladeEarly2020Base(_MacroKeyboard): + """ + Class for the Razer Blade Base (Early 2020) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0255 + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/blade-15/blade-15-base-model-spec-image-v2.png" + + +class RazerBladeLate2020Base(_MacroKeyboard): + """ + Class for the Razer Blade Late 2020 Base + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0268 + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/blade-15/shop/blade15-base-model-spec-image-v2.png" + + +class RazerBladeProLate2019(_RippleKeyboard): + """ + Class for the Razer Blade Pro (Late 2019) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x024C + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/razer-blade-pro-17/razer-blade-pro-17-2019-OGimage-1200x630.jpg" + + +class RazerBladeAdvancedLate2019(_RippleKeyboard): + """ + Class for the Razer Blade Advanced (Late 2019) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x024B + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/razer-blade-pro-17/razer-blade-pro-17-2019-OGimage-1200x630.jpg" + + +class RazerBladeProEarly2020(_RippleKeyboard): + """ + Class for the Razer Blade Pro (Early 2020) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0256 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_custom_effect', 'set_key_row', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1654/blade-pro-17-2020-2.png" + + +class RazerBlade2019StudioEdition(_RippleKeyboard): + """ + Class for the Razer Blade 15 Studio Edition (2019) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x024D + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/blade-15/shop/studio-ch41-1.jpg" + + +class RazerBladePro2019(_RippleKeyboard): + """ + Class for the Razer Blade Pro 17 (2019) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0234 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', + 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/razer-blade-pro-17/razer-blade-pro-17-2019-OGimage-1200x630.jpg" + + +class RazerBlade15Advanced2020(_RippleKeyboard): + """ + Class for the Razer Blade 15 Advanced (2020) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0253 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1651/razer-blade-15-advanced-2020.png" + + +class RazerBlade15Advanced2021(_RippleKeyboard): + """ + Class for the Razer Blade 15 Advanced (Mid 2021) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0276 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1778/1778-razerblade15advanced2021rz09-0409x-2.png" + + +class RazerBlade17Pro2021(_RippleKeyboard): + """ + Class for the Razer Blade 17 Pro (Mid 2021) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0279 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/5524/5524-1-en-v2.png" + + +class RazerBlade142021(_RippleKeyboard): + """ + Class for the Razer Blade 14 (2021) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0270 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/og-image/razer-blade-14-og-image-1200x630.jpg" + + +class RazerHuntsmanMini(_RippleKeyboard): + """ + Class for the Razer Huntsman Mini + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Huntsman_Mini_00000000001A(-if01)?-event-kbd') + USB_VID = 0x1532 + USB_PID = 0x0257 + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [5, 15] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1689/1689-huntsmanmini.png" + + +class RazerHuntsmanMiniJP(_RippleKeyboard): + """ + Class for the Razer Huntsman Mini JP + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Huntsman_Mini_00000000001A(-if01)?-event-kbd') + USB_VID = 0x1532 + USB_PID = 0x0269 + HAS_MATRIX = True + WAVE_DIRS = (0, 1) + MATRIX_DIMS = [5, 15] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://rzrwarranty.s3.amazonaws.com/4403e5e6b96d59dc95a278e257688e64a68f7b24945617653d68e3273877c01e.png" + + +class RazerBlade15AdvancedEarly2021(_RippleKeyboard): + """ + Class for the Razer Blade 15 Advanced (Early 2021) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x026D + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1761/blade-15-advanced-2021-rz09-0367x.png" + + +class RazerBlade17ProEarly2021(_RippleKeyboard): + """ + Class for the Razer Blade 17 Pro (Early 2021) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x026E + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/4025-16-EN-v1.png" + + +class RazerBladeEarly2021Base(_MacroKeyboard): + """ + Class for the Razer Blade Base (Early 2021) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x026F + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1756/blade-15-base-2021-rz09-0369x.png" + + +class RazerBladeEarly2022Base(_MacroKeyboard): + """ + Class for the Razer Blade Base (Early 2022) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x027A + METHODS = ['get_device_type_keyboard', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1756/blade-15-base-2021-rz09-0369x.png" + + +class RazerBlade172022(_RippleKeyboard): + """ + Class for the Razer Blade 17 (2022) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x028B + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/5896/5896-1-en-v2.png" + + +class RazerBlade142022(_RippleKeyboard): + """ + Class for the Razer Blade 14 (2022) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x028C + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/5896/5896-1-en-v2.png" + + +class RazerBlade15AdvancedEarly2022(_RippleKeyboard): + """ + Class for the Razer Blade 15 Advanced (Early 2022) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x028A + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/pnx.assets/a1ee4c5a780a401444be898fe93ade69/thumbnail-blade15-new-model.png" + + +class RazerBlackWidowV4(_RippleKeyboard): + """ + Class for the Razer BlackWidow V4 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_BlackWidow_V4(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0287 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [8, 23] + POLL_RATES = [125, 250, 500, 1000, 2000, 4000, 8000] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_wheel_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13219/13219-1-en-v1.png" + + +class RazerBlackWidowV4X(_RippleKeyboard): + """ + Class for the Razer BlackWidow V4 X + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_BlackWidow_V4_X(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0293 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [6, 22] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_wheel_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13223/13223-1-en-v1.png" + + +class RazerBlackWidowV4Pro(_RippleKeyboard): + """ + Class for the Razer BlackWidow V4 Pro + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_BlackWidow_V4_Pro(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x028D + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [8, 23] + POLL_RATES = [125, 250, 500, 1000, 2000, 4000, 8000] + METHODS = ['get_device_type_keyboard', 'set_wave_effect', 'set_wheel_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'get_game_mode', 'set_game_mode', 'get_macro_mode', 'set_macro_mode', + 'get_macro_effect', 'set_macro_effect', 'get_macros', 'delete_macro', 'add_macro', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/9703/9703-1-en-v1.png" + + +class RazerBlade142023(_RippleKeyboard): + """ + Class for the Razer Blade 14 (2023) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x029D + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13031/13031-1-en-v2.png" + + +class RazerBlade142024(_RippleKeyboard): + """ + Class for the Razer Blade 14 (2024) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02B6 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13031/13031-1-en-v2.png" + + +class RazerBlade152023(_RippleKeyboard): + """ + Class for the Razer Blade 15 (2023) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x029E + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/9696/9696-1-en-v2.png" + + +class RazerBlade162023(_RippleKeyboard): + """ + Class for the Razer Blade 16 (2023) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x029F + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/9668/9668-1-en-v2.png" + + +class RazerBlade162025(_RippleKeyboard): + """ + Class for the Razer Blade 16 (2025) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02C6 + HAS_MATRIX = True + MATRIX_DIMS = [6, 17] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/14806/14806-en-v1.png" + + +class RazerBlade182023(_RippleKeyboard): + """ + Class for the Razer Blade 18 (2023) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02A0 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/9676/9676-1-en-v1.png" + + +class RazerBlade182024(_RippleKeyboard): + """ + Class for the Razer Blade 18 (2024) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Blade(-if01)?-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x02B8 + HAS_MATRIX = True + MATRIX_DIMS = [6, 16] + METHODS = ['get_device_type_keyboard', 'get_logo_active', 'set_logo_active', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', + 'set_breath_dual_effect', 'set_custom_effect', 'set_key_row', + 'set_starlight_random_effect', 'set_starlight_single_effect', 'set_starlight_dual_effect', + 'set_ripple_effect', 'set_ripple_effect_random_colour'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/9676/9676-1-en-v1.png" diff --git a/openrazer/daemon/openrazer_daemon/hardware/monitor.py b/openrazer/daemon/openrazer_daemon/hardware/monitor.py new file mode 100644 index 00000000..c0b70eef --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/monitor.py @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Monitor class +""" +from openrazer_daemon.hardware.device_base import RazerDeviceBrightnessSuspend as _RazerDeviceBrightnessSuspend + + +class RazerRaptor27(_RazerDeviceBrightnessSuspend): + """ + Class for the Razer Raptor 27 + """ + USB_VID = 0x1532 + USB_PID = 0x0F12 + HAS_MATRIX = True + MATRIX_DIMS = [1, 12] + METHODS = ['get_device_type_accessory', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/ha0/h53/9081460162590/raptor-27-gallery-1.jpg" diff --git a/openrazer/daemon/openrazer_daemon/hardware/mouse.py b/openrazer/daemon/openrazer_daemon/hardware/mouse.py new file mode 100644 index 00000000..08f53436 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/mouse.py @@ -0,0 +1,2012 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Mouse class +""" +import re +from openrazer_daemon.hardware.device_base import RazerDeviceBrightnessSuspend as __RazerDeviceBrightnessSuspend, RazerDevice as __RazerDevice + + +class RazerViperMini(__RazerDevice): + """ + Class for the Razer Viper Mini + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Viper_Mini-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x008A + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness', + # Underglow/Logo use LOGO_LED + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1634/vipermini.png" + + DPI_MAX = 8500 + + +class RazerLanceheadWirelessWired(__RazerDevice): + """ + Class for the Razer Lancehead Wireless (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Lancehead_Wireless-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0070 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 16] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness', 'get_scroll_brightness', 'set_scroll_brightness', + 'get_left_brightness', 'set_left_brightness', 'get_right_brightness', 'set_right_brightness', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Left side + 'set_left_wave', 'set_left_static', 'set_left_spectrum', 'set_left_none', 'set_left_reactive', 'set_left_breath_random', 'set_left_breath_single', 'set_left_breath_dual', + # Right side + 'set_right_wave', 'set_right_static', 'set_right_spectrum', 'set_right_none', 'set_right_reactive', 'set_right_breath_random', 'set_right_breath_single', 'set_right_breath_dual', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1205/1205_lancehead.png" + + DPI_MAX = 16000 + + +class RazerLanceheadWirelessReceiver(RazerLanceheadWirelessWired): + """ + Class for the Razer Lancehead Wireless (Receiver) + """ + USB_PID = 0x006F + METHODS = RazerLanceheadWirelessWired.METHODS + ['set_charge_effect', 'set_charge_colour'] + + +class RazerLanceheadWired(__RazerDevice): + """ + Class for the Razer Lancehead (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Lancehead-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0059 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 16] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness', 'get_scroll_brightness', 'set_scroll_brightness', + 'get_left_brightness', 'set_left_brightness', 'get_right_brightness', 'set_right_brightness', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Left side + 'set_left_wave', 'set_left_static', 'set_left_spectrum', 'set_left_none', 'set_left_reactive', 'set_left_breath_random', 'set_left_breath_single', 'set_left_breath_dual', + # Right side + 'set_right_wave', 'set_right_static', 'set_right_spectrum', 'set_right_none', 'set_right_reactive', 'set_right_breath_random', 'set_right_breath_single', 'set_right_breath_dual', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1205/1205_lancehead.png" + + DPI_MAX = 16000 + + +class RazerLanceheadWireless(RazerLanceheadWired): + """ + Class for the Razer Lancehead (Wireless) + """ + USB_PID = 0x005A + METHODS = RazerLanceheadWired.METHODS + ['set_charge_effect', 'set_charge_colour'] + + +class RazerDeathAdderEssentialWhiteEdition(__RazerDevice): + """ + Class for the Razer DeathAdder Essential (White Edition) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_DeathAdder_Essential_White_Edition-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0071 + 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', 'set_logo_none', 'set_logo_breath_single', + # Scroll wheel + 'set_scroll_static', 'set_scroll_none', 'set_scroll_breath_single'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/da10m/carousel/razer-death-adder-gallery-25.png" + + DPI_MAX = 6400 + + +class RazerAbyssusEliteDVaEdition(__RazerDevice): + """ + Class for the Razer Abyssus Elite (D.Va Edition) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_D.Va_Razer_Abyssus_Elite-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x006A + 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', + # Underglow/Logo use LOGO_LED + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1288/d.va_abyssus_elite.png" + + DPI_MAX = 7200 + + +class RazerAbyssusEssential(__RazerDevice): + """ + Class for the Razer Abyssus Essential + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Abyssus_Essential-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x006B + 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', + # Backlight/Logo...same + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1290/1290_abyssusessential.png" + + DPI_MAX = 7200 + + +class RazerLanceheadTE(__RazerDevice): + """ + Class for the Razer Lancehead Tournament Edition + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Lancehead_TE-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0060 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 16] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness', 'get_scroll_brightness', 'set_scroll_brightness', + 'get_left_brightness', 'set_left_brightness', 'get_right_brightness', 'set_right_brightness', + # Logo + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Left side + 'set_left_wave', 'set_left_static', 'set_left_spectrum', 'set_left_none', 'set_left_reactive', 'set_left_breath_random', 'set_left_breath_single', 'set_left_breath_dual', + # Right side + 'set_right_wave', 'set_right_static', 'set_right_spectrum', 'set_right_none', 'set_right_reactive', 'set_right_breath_random', 'set_right_breath_single', 'set_right_breath_dual', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1203/1206_lanceheadte.png" + + DPI_MAX = 16000 + + +class RazerMambaChromaWireless(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Mamba Chroma (Wireless) + """ + USB_VID = 0x1532 + USB_PID = 0x0045 + HAS_MATRIX = True + MATRIX_DIMS = [1, 15] + METHODS = ['get_device_type_mouse', 'get_battery', 'is_charging', 'set_backlight_wave', + 'set_backlight_static', 'set_backlight_spectrum', 'set_backlight_reactive', 'set_backlight_none', 'set_backlight_breath_random', + 'set_backlight_breath_single', 'set_backlight_breath_dual', 'set_custom_effect', 'set_key_row', + 'set_charge_effect', 'set_charge_colour', + 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/609/609_mamba_500x500.png" + + DPI_MAX = 16000 + + +class RazerMambaChromaWired(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Mamba Chroma (Wired) + """ + USB_VID = 0x1532 + USB_PID = 0x0044 + HAS_MATRIX = True + MATRIX_DIMS = [1, 15] + METHODS = ['get_device_type_mouse', 'set_backlight_wave', + 'set_backlight_static', 'set_backlight_spectrum', 'set_backlight_reactive', 'set_backlight_none', 'set_backlight_breath_random', + 'set_backlight_breath_single', 'set_backlight_breath_dual', 'set_custom_effect', 'set_key_row', 'max_dpi', + 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', 'get_battery', 'is_charging'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/609/609_mamba_500x500.png" + + DPI_MAX = 16000 + + +class RazerMambaTE(__RazerDevice): + """ + Class for the Razer Mamba Tournament Edition + """ + USB_VID = 0x1532 + USB_PID = 0x0046 + HAS_MATRIX = True + MATRIX_DIMS = [1, 16] + METHODS = ['get_device_type_mouse', 'get_backlight_brightness', 'set_backlight_brightness', 'set_backlight_wave', + 'set_backlight_static', 'set_backlight_spectrum', 'set_backlight_reactive', 'set_backlight_none', 'set_backlight_breath_random', + 'set_backlight_breath_single', 'set_backlight_breath_dual', 'set_custom_effect', 'set_key_row', 'max_dpi', + 'get_dpi_xy', 'set_dpi_xy'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/606/606_mambate_500x500.png" + + DPI_MAX = 16000 + + +class RazerAbyssus(__RazerDevice): + """ + Class for the Razer Abyssus + """ + USB_VID = 0x1532 + USB_PID = 0x0042 + METHODS = ['get_device_type_mouse', 'set_logo_none', 'set_logo_on', 'get_poll_rate', 'set_poll_rate'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/274/abyssus2014_500x500.png" + + +class RazerImperator(__RazerDevice): + """ + Class for the Razer Imperator 2012 + """ + USB_VID = 0x1532 + USB_PID = 0x002F + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/215/215_imperator.png" + + DPI_MAX = 6400 + + +class RazerOuroboros(__RazerDevice): + """ + Class for the Razer Ouroboros + """ + USB_VID = 0x1532 + USB_PID = 0x0032 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_poll_rate', 'set_poll_rate', 'set_scroll_none', 'set_scroll_on', 'get_scroll_brightness', 'set_scroll_brightness', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/26/26_ouroboros.png" + + DPI_MAX = 8200 + + +class RazerOrochi2013(__RazerDevice): + """ + Class for the Razer Orochi 2013 + """ + USB_VID = 0x1532 + USB_PID = 0x0039 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_poll_rate', 'set_poll_rate', 'set_scroll_none', 'set_scroll_on'] + + DPI_MAX = 6400 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/612/612_orochi_2015.png" + + +class RazerOrochiWired(__RazerDevice): + """ + Class for the Razer Orochi (Wired) + """ + USB_VID = 0x1532 + USB_PID = 0x0048 + METHODS = ['get_device_type_mouse', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_on', + 'set_backlight_static', 'set_backlight_spectrum', 'set_backlight_reactive', 'set_backlight_none', 'set_backlight_breath_random', + 'set_backlight_breath_single', 'set_backlight_breath_dual', + 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_poll_rate', 'set_poll_rate'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/612/612_orochi_2015.png" + + DPI_MAX = 8200 + + +class RazerDeathAdderChroma(__RazerDevice): + """ + Class for the Razer DeathAdder Chroma + """ + USB_VID = 0x1532 + USB_PID = 0x0043 + METHODS = ['get_device_type_mouse', + 'get_logo_brightness', 'set_logo_brightness', 'set_logo_none', 'set_logo_static', 'set_logo_breath_single', 'set_logo_blinking', 'set_logo_spectrum', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_static', 'set_scroll_breath_single', 'set_scroll_blinking', 'set_scroll_spectrum', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/278/278_deathadder_chroma.png" + + DPI_MAX = 10000 + + +class RazerDeathAdder2000(__RazerDevice): + """ + Class for the Razer DeathAdder 2000 + """ + USB_VID = 0x1532 + USB_PID = 0x004F + METHODS = ['get_device_type_mouse', + 'get_logo_brightness', 'set_logo_brightness', 'set_logo_none', 'set_logo_on', 'set_logo_breath_mono', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_on', 'set_scroll_breath_mono', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/da10m/carousel/razer-death-adder-gallery-09.png" + + DPI_MAX = 2000 + + +class RazerDeathAdder2013(__RazerDevice): + """ + Class for the Razer DeathAdder 2013 + """ + USB_VID = 0x1532 + USB_PID = 0x0037 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_scroll_none', 'set_scroll_static', 'set_scroll_breath_single', 'set_scroll_blinking', + 'set_logo_none', 'set_logo_static', 'set_logo_breath_single', 'set_logo_blinking'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/561/561_deathadder_classic.png" + + DPI_MAX = 6400 + + +class RazerNagaHexV2(__RazerDevice): + """ + Class for the Razer Naga Hex V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Naga_Hex_V2-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0050 + HAS_MATRIX = True + DEDICATED_MACRO_KEYS = True + MATRIX_DIMS = [1, 3] + 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', + # Thumbgrid is technically backlight ID + 'get_backlight_brightness', 'set_backlight_brightness', + 'set_backlight_static', 'set_backlight_spectrum', 'set_backlight_reactive', 'set_backlight_none', 'set_backlight_breath_random', 'set_backlight_breath_single', 'set_backlight_breath_dual', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # #Macros + 'get_macros', 'delete_macro', 'add_macro', + # Can set Logo, Scroll and thumbgrid with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/715/715_nagahexv2_500x500.png" + + DPI_MAX = 16000 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # self.key_manager = _NagaHexV2KeyManager(self._device_number, self.event_files, self, use_epoll=True, testing=self._testing, should_grab_event_files=True) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerNaga(__RazerDevice): + """ + Class for the Razer Naga + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Naga-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0015 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on', 'set_backlight_none', 'set_backlight_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/40/razer-naga-molten-gallery-4.png" + + DPI_MAX = 5600 + + +class RazerNaga2012(__RazerDevice): + """ + Class for the Razer Naga 2012 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Naga-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x002E + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on', 'set_backlight_none', 'set_backlight_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/39/razer-naga-gallery-4.png" + + DPI_MAX = 5600 + + +class RazerNagaChroma(__RazerDevice): + """ + Class for the Razer Naga Chroma + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Naga_Chroma-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0053 + HAS_MATRIX = True + DEDICATED_MACRO_KEYS = True + MATRIX_DIMS = [1, 3] + METHODS = ['get_device_type_mouse', 'get_dpi_xy', 'set_dpi_xy', 'max_dpi', + 'get_poll_rate', 'set_poll_rate', + 'get_backlight_brightness', 'set_backlight_brightness', + 'get_logo_brightness', 'set_logo_brightness', + 'get_scroll_brightness', 'set_scroll_brightness', + # Thumbgrid is technically backlight ID + 'set_backlight_static', 'set_backlight_spectrum', 'set_backlight_reactive', 'set_backlight_none', 'set_backlight_breath_random', 'set_backlight_breath_single', 'set_backlight_breath_dual', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # #Macros + 'get_macros', 'delete_macro', 'add_macro', + # Can set Logo, Scroll and thumbgrid with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/636/636_naga_chroma.png" + + DPI_MAX = 16000 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # self.key_manager = _NagaHexV2KeyManager(self._device_number, self.event_files, self, use_epoll=True, testing=self._testing, should_grab_event_files=True) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerNagaTrinity(__RazerDevice): + """ + Class for the Razer Naga Trinity + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Naga_Trinity-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0067 + HAS_MATRIX = False # TODO Device supports matrix, driver missing + DEDICATED_MACRO_KEYS = True + # MATRIX_DIMS = [1, 3] + METHODS = ['get_device_type_mouse', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'get_brightness', 'set_brightness', 'set_static_effect', 'max_dpi'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1251/1251_razer_naga_trinity.png" + + DPI_MAX = 16000 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # self.key_manager = _NagaHexV2KeyManager(self._device_number, self.event_files, self, use_epoll=True, testing=self._testing, should_grab_event_files=True) + + def _close(self): + """ + Close the key manager + """ + super()._close() + + # self.key_manager.close() + + +class RazerNagaHex(__RazerDevice): + """ + Class for the Razer Naga Hex + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Naga_Hex-if01-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0041 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/23/23_naga_hex.png" + + DPI_MAX = 5600 + + +class RazerNagaHexRed(__RazerDevice): + """ + Class for the Razer Naga Hex (Red) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Naga_Hex-if01-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0036 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/12/razer-naga-hex-gallery-12.png" + + DPI_MAX = 5600 + + +class RazerTaipan(__RazerDevice): + """ + Class for the Razer Taipan + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Taipan-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0034 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/19/19_taipan.png" + + DPI_MAX = 8200 + + +class RazerDeathAdderElite(__RazerDevice): + """ + Class for the Razer DeathAdder Elite + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_DeathAdder_Elite-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x005C + HAS_MATRIX = True + MATRIX_DIMS = [1, 2] + 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', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/724/724_deathadderelite_500x500.png" + + DPI_MAX = 16000 + + +class RazerDiamondbackChroma(__RazerDevice): + """ + Class for the Razer Diamondback Chroma + """ + USB_VID = 0x1532 + USB_PID = 0x004C + HAS_MATRIX = True + MATRIX_DIMS = [1, 21] + METHODS = ['get_device_type_mouse', 'get_backlight_brightness', 'set_backlight_brightness', 'set_backlight_wave', + 'set_backlight_static', 'set_backlight_spectrum', 'set_backlight_reactive', 'set_backlight_none', 'set_backlight_breath_random', + 'set_backlight_breath_single', 'set_backlight_breath_dual', 'set_custom_effect', 'set_key_row', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy'] + + DPI_MAX = 16000 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/613/613_diamondback.png" + + +class RazerDeathAdder3_5G(__RazerDevice): + """ + Class for the Razer DeathAdder 3.5G + """ + USB_VID = 0x1532 + USB_PID = 0x0016 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', + 'get_poll_rate', 'set_poll_rate', 'get_dpi_xy', 'set_dpi_xy', 'available_dpi', 'max_dpi', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on'] + + AVAILABLE_DPI = [450, 900, 1800, 3500] + DPI_MAX = 3500 + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/da10m/carousel/razer-death-adder-gallery-04.png" + + +class RazerDeathAdder3_5GBlack(__RazerDevice): + """ + Class for the Razer DeathAdder 3.5G Black + """ + USB_VID = 0x1532 + USB_PID = 0x0029 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', + 'get_poll_rate', 'set_poll_rate', 'get_dpi_xy', 'set_dpi_xy', 'available_dpi', 'max_dpi'] + + AVAILABLE_DPI = [450, 900, 1800, 3500] + DPI_MAX = 3500 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/33/razer-deathadder-be-gallery-3.png" + + +class RazerMamba2012Wireless(__RazerDevice): + """ + Class for the Razer Mamba 2012 (Wireless) + """ + USB_VID = 0x1532 + USB_PID = 0x0025 + METHODS = ['get_device_type_mouse', 'get_battery', 'is_charging', + 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_static', 'set_scroll_spectrum'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/192/192_mamba_2012.png" + + DPI_MAX = 6400 + + +class RazerMamba2012Wired(__RazerDevice): + """ + Class for the Razer Mamba 2012 (Wired) + """ + USB_VID = 0x1532 + USB_PID = 0x0024 + METHODS = ['get_device_type_mouse', + 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_static', 'set_scroll_spectrum', + 'get_battery', 'is_charging'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/192/192_mamba_2012.png" + + DPI_MAX = 6400 + + +class RazerMambaWirelessWired(__RazerDevice): + """ + Class for the Razer Mamba Wireless (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Mamba_Wireless_000000000000-if0(1|2)-event-kbd') + USB_VID = 0x1532 + USB_PID = 0x0073 + HAS_MATRIX = True + MATRIX_DIMS = [1, 16] + 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', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1404/1404_mamba_wireless.png" + + DPI_MAX = 16000 + + +class RazerMambaWirelessReceiver(RazerMambaWirelessWired): + """ + Class for the Razer Mamba Wireless (Receiver) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Mamba_Wireless_Receiver-if0(1|2)-event-kbd') + USB_PID = 0x0072 + METHODS = RazerMambaWirelessWired.METHODS + ['set_charge_effect', 'set_charge_colour'] + + +class RazerNaga2014(__RazerDevice): + """ + Class for the Razer Naga 2014 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Naga_2014-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0040 + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on', 'set_backlight_none', 'set_backlight_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/227/227_razer_naga_2014.png" + + DPI_MAX = 8200 + + +class RazerOrochi2011(__RazerDevice): + """ + Class for the Razer Orochi 2011 + """ + USB_VID = 0x1532 + USB_PID = 0x0013 + EVENT_FILE_REGEX = re.compile(r'.*Razer_Orochi-if01-event-kbd') + + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on', 'set_scroll_none', 'set_scroll_on'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/612/612_orochi_2015.png" + + DPI_MAX = 4000 + + +class RazerAbyssusV2(__RazerDevice): + """ + Class for the Razer Abyssus V2 + """ + USB_VID = 0x1532 + USB_PID = 0x005B + METHODS = ['get_device_type_mouse', + 'get_logo_brightness', 'set_logo_brightness', 'set_logo_none', 'set_logo_static', 'set_logo_breath_single', 'set_logo_blinking', 'set_logo_spectrum', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_static', 'set_scroll_breath_single', 'set_scroll_blinking', 'set_scroll_spectrum', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/721/721_abyssusv2.png" + + DPI_MAX = 5000 + + +class RazerAbyssus1800(__RazerDevice): + """ + Class for the Razer Abyssus 1800 + """ + USB_VID = 0x1532 + USB_PID = 0x0020 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on'] + + DPI_MAX = 1800 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1277/1277_abyssus_2000.png" + + +class RazerAbyssus2000(__RazerDevice): + """ + Class for the Razer Abyssus 2000 + """ + USB_VID = 0x1532 + USB_PID = 0x005E + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on'] + + DPI_MAX = 2000 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1277/1277_abyssus_2000.png" + + +class RazerDeathAdder3500(__RazerDevice): + """ + Class for the Razer DeathAdder 3500 + """ + USB_VID = 0x1532 + USB_PID = 0x0054 + METHODS = ['get_device_type_mouse', + 'get_logo_brightness', 'set_logo_brightness', 'set_logo_none', 'set_logo_static', 'set_logo_breath_single', 'set_logo_blinking', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_static', 'set_scroll_breath_single', 'set_scroll_blinking', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/561/561_deathadder_classic.png" + + DPI_MAX = 3500 + + +class RazerViperUltimateWired(__RazerDevice): + """ + Class for the Razer Viper Ultimate (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Viper_Ultimate_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x007A + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1577/ee_photo.png" + + DPI_MAX = 20000 + + +class RazerViperUltimateWireless(RazerViperUltimateWired): + """ + Class for the Razer Viper Ultimate (Wireless) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Viper_Ultimate_Dongle-if0(1|2)-event-kbd') + + USB_PID = 0x007B + METHODS = RazerViperUltimateWired.METHODS + ['set_charge_effect', 'set_charge_colour'] + + +class RazerViper(__RazerDevice): + """ + Class for the Razer Viper + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Viper-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0078 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1539/1539_viper.png" + + DPI_MAX = 16000 + + +class RazerDeathAdderEssential(__RazerDevice): + """ + Class for the Razer DeathAdder Essential + """ + USB_VID = 0x1532 + USB_PID = 0x006E + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + # Logo + 'get_logo_brightness', 'set_logo_brightness', + 'set_logo_static', 'set_logo_none', 'set_logo_breath_single', + # Scroll wheel + 'get_scroll_brightness', 'set_scroll_brightness', + 'set_scroll_static', 'set_scroll_none', 'set_scroll_breath_single'] + + DPI_MAX = 6400 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1385/1385_deathadderessential.png" + + +class RazerDeathAdderEssential2021(__RazerDevice): + """ + Class for the Razer DeathAdder Essential (2021) + """ + USB_VID = 0x1532 + USB_PID = 0x0098 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + # Logo + 'get_logo_brightness', 'set_logo_brightness', + 'set_logo_static', 'set_logo_none', 'set_logo_breath_single'] + + DPI_MAX = 6400 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1385/1385_deathadderessential.png" + + +class RazerMambaElite(__RazerDevice): + """ + Class for the Razer Mamba Elite + """ + USB_VID = 0x1532 + USB_PID = 0x006C + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 20] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_poll_rate', 'set_poll_rate', + # Logo logo_led_brightness/logo_matrix_effect_breath/... + 'get_logo_brightness', 'set_logo_brightness', + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel scroll_led_brightness/scroll_matrix_effect_breath/... + 'get_scroll_brightness', 'set_scroll_brightness', + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Left side left_led_brightness/left_matrix_effect_breath/... + 'get_left_brightness', 'set_left_brightness', + 'set_left_wave', 'set_left_static', 'set_left_spectrum', 'set_left_none', 'set_left_reactive', 'set_left_breath_random', 'set_left_breath_single', 'set_left_breath_dual', + # Right side right_led_brightness/right_matrix_effect_breath/... + 'get_right_brightness', 'set_right_brightness', + 'set_right_wave', 'set_right_static', 'set_right_spectrum', 'set_right_none', 'set_right_reactive', 'set_right_breath_random', 'set_right_breath_single', 'set_right_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DPI_MAX = 16000 + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1390/1390_mamba_elite.png" + + +class RazerNagaLeftHanded2020(__RazerDevice): + """ + Class for the Razer Naga Left Handed Edition 2020 + """ + USB_VID = 0x1532 + USB_PID = 0x008D + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 3] + + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_poll_rate', 'set_poll_rate', + # Macros + 'get_macros', 'delete_macro', 'add_macro', + # Logo + 'get_logo_brightness', 'set_logo_brightness', + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'get_scroll_brightness', 'set_scroll_brightness', + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Right side = thumbgrid + 'get_right_brightness', 'set_right_brightness', + 'set_right_wave', 'set_right_static', 'set_right_spectrum', 'set_right_none', 'set_right_reactive', 'set_right_breath_random', 'set_right_breath_single', 'set_right_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DPI_MAX = 20000 + + DEVICE_IMAGE = "https://rzrwarranty.s3.amazonaws.com/cee694cd7526df413008167b7566af310985321b20c57f3dc42e5cbd773f2417.png" + + +class RazerNagaProWired(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Naga Pro (Wired) + """ + USB_VID = 0x1532 + USB_PID = 0x008F + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 3] + + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', 'get_dpi_stages', 'set_dpi_stages', + # Macros + 'get_macros', 'delete_macro', 'add_macro', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'get_logo_brightness', 'set_logo_brightness', + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'get_scroll_brightness', 'set_scroll_brightness', + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Thumbgrid + 'set_static_effect', 'set_spectrum_effect', 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DPI_MAX = 20000 + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/hfd/ha6/9080569528350/razer-naga-pro-500x500.png" + + +class RazerNagaProWireless(RazerNagaProWired): + """ + Class for the Razer Naga Pro (Wireless) + """ + USB_PID = 0x0090 + METHODS = RazerNagaProWired.METHODS + ['set_charge_effect', 'set_charge_colour'] + + +class RazerNagaV2ProWired(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Naga V2 Pro (Wired) + """ + USB_VID = 0x1532 + USB_PID = 0x00A7 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 3] + + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', 'get_dpi_stages', 'set_dpi_stages', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'get_logo_brightness', 'set_logo_brightness', + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Thumbgrid + 'set_static_effect', 'set_spectrum_effect', 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DPI_MAX = 30000 + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/6292/6292-1-en-v1.png" + + +class RazerNagaV2ProWireless(RazerNagaV2ProWired): + """ + Class for the Razer Naga V2 Pro (Wireless) + """ + USB_PID = 0x00A8 + METHODS = RazerNagaV2ProWired.METHODS + ['set_charge_effect', 'set_charge_colour'] + + +class RazerDeathAdder1800(__RazerDevice): + """ + Class for the Razer DeathAdder 1800 + """ + USB_VID = 0x1532 + USB_PID = 0x0038 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'set_logo_none', 'set_logo_on'] + + DPI_MAX = 1800 + + DEVICE_IMAGE = "https://rzrwarranty.s3.amazonaws.com/a7daf40ad78c9584a693e310effa956019cdcd081391f93f71a7cd36d3dc577e.png" + + +class RazerBasilisk(__RazerDevice): + """ + Class for the Razer Basilisk + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0064 + HAS_MATRIX = True + MATRIX_DIMS = [1, 2] + 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', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1241/1241_basilisk.png" + + DPI_MAX = 16000 + + +class RazerBasiliskEssential(__RazerDevice): + """ + Class for the Razer Basilisk Essential + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_Essential-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0065 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', + # Logo + 'get_logo_brightness', 'set_logo_brightness', 'set_logo_spectrum', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', 'set_logo_static', 'set_logo_none', + # Can set LOGO with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/h19/h61/9080617500702/Basilisk-Essential-500x500.png" + + DPI_MAX = 6400 + + +class RazerBasiliskUltimateWired(__RazerDevice): + """ + Class for the Razer Basilisk Ultimate + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_Ultimate_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0086 + HAS_MATRIX = True + MATRIX_DIMS = [1, 14] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'get_logo_brightness', 'set_logo_brightness', + # Spectrum + 'set_logo_spectrum', + # Reactive + 'set_logo_reactive', + # Breath + 'set_logo_breath_random', + 'set_logo_breath_single', + 'set_logo_breath_dual', + # Static + 'set_logo_static', + # None + 'set_logo_none', + # Scroll wheel + 'get_scroll_brightness', 'set_scroll_brightness', + # Spectrum + 'set_scroll_spectrum', + # Reactive + 'set_scroll_reactive', + # Breath + 'set_scroll_breath_random', + 'set_scroll_breath_single', + 'set_scroll_breath_dual', + # Static + 'set_scroll_static', + # None + 'set_scroll_none', + 'get_left_brightness', 'set_left_brightness', 'get_right_brightness', 'set_right_brightness', + # Left side + 'set_left_wave', 'set_left_static', 'set_left_spectrum', 'set_left_none', 'set_left_reactive', 'set_left_breath_random', 'set_left_breath_single', 'set_left_breath_dual', + # Right side + 'set_right_wave', 'set_right_static', 'set_right_spectrum', 'set_right_none', 'set_right_reactive', 'set_right_breath_random', 'set_right_breath_single', 'set_right_breath_dual', + + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1590/1590_basilisk_ultimate.png" + + DPI_MAX = 20000 + + +class RazerBasiliskUltimateReceiver(RazerBasiliskUltimateWired): + USB_PID = 0x0088 + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_Ultimate_Dongle-if0(1|2)-event-kbd') + METHODS = RazerBasiliskUltimateWired.METHODS + \ + ['set_charge_effect', 'set_charge_colour'] + + +class RazerBasiliskV2(__RazerDevice): + """ + 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, 2] + 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', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # 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 + + +class RazerBasiliskV3(__RazerDevice): + """ + Class for the Razer Basilisk V3 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_V3-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0099 + HAS_MATRIX = True + MATRIX_DIMS = [1, 11] + METHODS = ['get_device_type_mouse', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_brightness', 'set_brightness', + 'get_logo_brightness', 'set_logo_brightness', + 'get_scroll_brightness', 'set_scroll_brightness', + # Scroll wheel controls + 'get_scroll_mode', 'set_scroll_mode', + 'get_scroll_acceleration', 'set_scroll_acceleration', + 'get_scroll_smart_reel', 'set_scroll_smart_reel', + # All LEDs (partial support) + 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', + # Logo (partial support) + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', + # Scroll wheel (partial support) + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', + # Can set custom matrix effects + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/pages/basilisk-v3-4D578898E8144Le8da21dde32b7a9f5f/basilisk.png" + + DPI_MAX = 26000 + + +class RazerDeathAdderV2(__RazerDevice): + """ + Class for the Razer DeathAdder V2 + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_DeathAdder_V2-if0(1|2)-event-kbd') + 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', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Scroll wheel + 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Can set LOGO and Scroll with custom + 'set_custom_effect', 'set_key_row'] + + USB_VID = 0x1532 + USB_PID = 0x0084 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1612/1612_razerdeathadderv2.png" + + DPI_MAX = 20000 + + +class RazerDeathAdderV2ProWired(__RazerDevice): + """ + Class for the Razer DeathAdder V2 Pro (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*1532_Razer_DeathAdder_V2_Pro_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x007C + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', 'set_poll_rate', 'get_logo_brightness', 'set_logo_brightness', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1714/comp_1_00000.png" + + DPI_MAX = 20000 + + +class RazerDeathAdderV2ProWireless(RazerDeathAdderV2ProWired): + """ + Class for the Razer DeathAdder V2 Pro (Wireless) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_DeathAdder_V2_Pro_000000000000-if0(1|2)-event-kbd') + + USB_PID = 0x007D + METHODS = RazerDeathAdderV2ProWired.METHODS + ['set_charge_effect', 'set_charge_colour'] + + +class RazerAtherisReceiver(__RazerDevice): + """ + Class for the Razer Atheris (Receiver) + """ + USB_VID = 0x1532 + USB_PID = 0x0062 + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Atheris_-_Mobile_Gaming_Mouse-if0(1|2)-event-kbd') + METHODS = ['get_device_type_mouse', 'get_poll_rate', 'set_poll_rate', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', + 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1234/1234_atheris.png" + + DPI_MAX = 7200 + + +class RazerBasiliskXHyperSpeed(__RazerDevice): + """ + Class for the Razer Basilisk X HyperSpeed + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_X_HyperSpeed-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0083 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', + 'set_poll_rate', 'get_battery', 'is_charging', 'get_idle_time', + 'set_idle_time', 'get_low_battery_threshold', + 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1589/1589_basilisk_x__hyperspeed.png" + + DPI_MAX = 16000 + + +class RazerOrochiV2Receiver(__RazerDevice): + """ + Class for the Razer Orochi V2 (Receiver) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Orochi_V2_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x0094 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', 'get_poll_rate', + 'set_poll_rate', 'get_battery', 'is_charging', 'get_idle_time', + 'set_idle_time', 'get_low_battery_threshold', + 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/OrochiV2-1-en-v1.png" + + DPI_MAX = 18000 + + +class RazerOrochiV2Bluetooth(RazerOrochiV2Receiver): + """ + Class for the Razer Orochi V2 (Bluetooth) + """ + USB_PID = 0x0095 + + +class RazerNagaX(__RazerDevice): + """ + Class for the Razer Naga X + """ + USB_VID = 0x1532 + USB_PID = 0x0096 + HAS_MATRIX = True + WAVE_DIRS = (1, 2) + MATRIX_DIMS = [1, 2] + + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + # Macros + 'get_macros', 'delete_macro', 'add_macro', + # Scroll wheel + 'get_scroll_brightness', 'set_scroll_brightness', + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual', + # Left side = thumbgrid + 'get_left_brightness', 'set_left_brightness', + 'set_left_wave', 'set_left_static', 'set_left_spectrum', 'set_left_none', 'set_left_reactive', 'set_left_breath_random', 'set_left_breath_single', 'set_left_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + DPI_MAX = 18000 + + DEVICE_IMAGE = "https://dl.razerzone.com/src/3993-1-EN-V2.png" + + +class RazerDeathAdderV2Mini(__RazerDevice): + """ + Class for the Razer DeathAdder V2 Mini + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_DeathAdder_V2_Mini-if0(1|2)-event-kbd') + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_logo_brightness', 'set_logo_brightness', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + USB_VID = 0x1532 + USB_PID = 0x008C + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1692/deathadder-v2-mini.png" + + DPI_MAX = 8500 + + +class RazerViper8KHz(__RazerDevice): + """ + Class for the Razer Viper 8KHz + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Viper_8KHz-if0(1|2)-event-kbd') + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'get_logo_brightness', 'set_logo_brightness', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual'] + USB_VID = 0x1532 + USB_PID = 0x0091 + DEVICE_IMAGE = "https://dl.razerzone.com/Images/Viper%208KHz/Viper8khz.png" + + DPI_MAX = 20000 + + POLL_RATES = [125, 500, 1000, 2000, 4000, 8000] + + +class RazerViperMiniSEWired(__RazerDevice): + """ + Class for the Razer Viper Mini SE (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Viper_Mini_Signature_Edition_000000000000-if0(1|2)-event-kbd') + USB_VID = 0x1532 + USB_PID = 0x009E + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/9682/9682-1-en-v1.png" + + DPI_MAX = 30000 + + POLL_RATES = [125, 500, 1000] + + +class RazerViperMiniSEWireless(RazerViperMiniSEWired): + """ + Class for the Razer Viper Mini SE (Wireless) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Viper_Mini_Signature_Edition-if0(1|2)-event-kbd') + USB_PID = 0x009F + + METHODS = RazerViperMiniSEWired.METHODS + ['set_hyperpolling_wireless_dongle_indicator_led_mode'] + + POLL_RATES = [125, 500, 1000, 2000, 4000, 8000] + + +class RazerNagaEpicChromaWired(__RazerDevice): + """ + Class for the Razer Naga Epic Chroma (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Naga_Epic_Chroma-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x003E + METHODS = ['get_firmware', 'get_matrix_dims', 'has_matrix', 'get_device_name', 'get_device_type_mouse', 'get_battery', 'is_charging', + 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_poll_rate', 'set_poll_rate', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_static', 'set_scroll_breath_single', 'set_scroll_spectrum', + 'get_backlight_brightness', 'set_backlight_brightness', 'set_backlight_none', 'set_backlight_static', 'set_backlight_breath_single', 'set_backlight_spectrum'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/products/20776/rzrnagaepicchroma_04.png" + + DPI_MAX = 8200 + + +class RazerNagaEpicChromaWireless(RazerNagaEpicChromaWired): + """ + Class for the Razer Naga Epic Chroma (Wireless) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Naga_Epic_Chroma_Dock-if0(1|2)-event-kbd') + + USB_PID = 0x003F + + +class RazerProClickReceiver(__RazerDevice): + """ + Class for the Razer Pro Click (Receiver) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Pro_Click-if0(1|2)-event-kbd') + USB_VID = 0x1532 + USB_PID = 0x0077 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'get_idle_time', 'set_idle_time', + + 'get_battery', 'is_charging', + 'get_low_battery_threshold', 'set_low_battery_threshold'] + DEVICE_IMAGE = "https://dl.razerzone.com/src/3802-0-en-v1.png" + + DPI_MAX = 16000 + + POLL_RATES = [125, 500, 1000] + + +class RazerProClickWired(RazerProClickReceiver): + """ + Class for the Razer Pro Click (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*1532_Razer_Pro_Click_000000000000-if0(1|2)-event-kbd') + USB_PID = 0x0080 + + +class RazerDeathAdderV2XHyperSpeed(__RazerDevice): + """ + Class for the Razer DeathAdder V2 X HyperSpeed + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_DeathAdder_V2_X_HyperSpeed_000000000000-if0(1|2)-event-kbd') + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + USB_VID = 0x1532 + USB_PID = 0x009C + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/he8/h51/9250345058334/deathadder-v2-x-hyperspeed-500x500.png" + + DPI_MAX = 14000 + + +class RazerNagaEpic(__RazerDevice): + """ + Class for the Razer Naga Epic + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Razer_Naga_Epic-if01-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x001F + DEDICATED_MACRO_KEYS = True + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy_byte', 'set_dpi_xy_byte', 'get_poll_rate', 'set_poll_rate', + 'get_scroll_brightness', 'set_scroll_brightness', 'set_scroll_none', 'set_scroll_static', 'set_scroll_spectrum', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://hwimg.nl/Razer_naga-epic.png" + + DPI_MAX = 5600 + + +class RazerViperV2ProWired(__RazerDevice): + """ + Class for the Razer Viper V2 Pro (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Viper_V2_Pro_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00A5 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6048-1-en-v10.png" + + DPI_MAX = 30000 + + +class RazerViperV2ProWireless(RazerViperV2ProWired): + """ + Class for the Razer Viper V2 Pro (Wireless) + """ + + USB_PID = 0x00A6 + + +class RazerCobraProWired(__RazerDevice): + """ + Class for the Razer Cobra Pro (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Cobra_Pro-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00AF + + METHODS = ['get_device_type_mouse', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_brightness', 'set_brightness', + 'get_logo_brightness', 'set_logo_brightness', + 'get_scroll_brightness', 'set_scroll_brightness', + # All LEDs (partial support) + 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', 'set_none_effect', + # Logo (partial support) + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', + # Scroll wheel (partial support) + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13182/13182-1-en-v2.png" + + DPI_MAX = 30000 + + +class RazerCobraProWireless(RazerCobraProWired): + """ + Class for the Razer Cobra Pro (Wireless) + """ + USB_PID = 0x00B0 + + +class RazerDeathAdderV3(__RazerDevice): + """ + Class for the Razer DeathAdder V3 + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_DeathAdder_V3-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00B2 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates'] + + POLL_RATES = [125, 500, 1000, 2000, 4000, 8000] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6124/6124-1-en-v2.png" + + DPI_MAX = 30000 + + +class RazerDeathAdderV3ProWired(__RazerDevice): + """ + Class for the Razer DeathAdder V3 Pro (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_DeathAdder_V3_Pro_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00B6 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6130/6130-1-en-v2.png" + + DPI_MAX = 35000 + + +class RazerDeathAdderV3ProWireless(RazerDeathAdderV3ProWired): + """ + Class for the Razer DeathAdder V3 Pro (Wireless) + """ + + USB_PID = 0x00B7 + + +class RazerDeathAdderV3ProWired_Alternate(RazerDeathAdderV3ProWired): + """ + Class for the Razer DeathAdder V3 Pro (Wired) + """ + USB_PID = 0x00C2 + + +class RazerDeathAdderV3ProWireless_Alternate(RazerDeathAdderV3ProWireless): + """ + Class for the Razer DeathAdder V3 Pro (Wireless) + """ + USB_PID = 0x00C3 + + +class RazerBasiliskV3ProWired(__RazerDevice): + """ + Class for the Razer Basilisk V3 Pro (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_V3_Pro_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00AA + HAS_MATRIX = True + MATRIX_DIMS = [1, 13] + METHODS = ['get_device_type_mouse', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_brightness', 'set_brightness', + 'get_logo_brightness', 'set_logo_brightness', + 'get_scroll_brightness', 'set_scroll_brightness', + # Scroll wheel controls + 'get_scroll_mode', 'set_scroll_mode', + 'get_scroll_acceleration', 'set_scroll_acceleration', + 'get_scroll_smart_reel', 'set_scroll_smart_reel', + # All LEDs (partial support) + 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', 'set_none_effect', + # Logo (partial support) + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', + # Scroll wheel (partial support) + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', + # Can set custom matrix effects + 'set_custom_effect', 'set_key_row', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/6220/6220-4-en-v1.png" + + DPI_MAX = 30000 + + +class RazerBasiliskV3ProWireless(RazerBasiliskV3ProWired): + """ + Class for the Razer Basilisk V3 Pro (Wireless) + """ + + USB_PID = 0x00AB + + +class RazerBasiliskV3Pro35KWired(RazerBasiliskV3ProWired): + """ + Class for the Razer Basilisk V3 Pro 35K (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_V3_Pro_35K_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00CC + HAS_MATRIX = True + MATRIX_DIMS = [1, 13] + METHODS = ['get_device_type_mouse', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_brightness', 'set_brightness', + 'get_logo_brightness', 'set_logo_brightness', + 'get_scroll_brightness', 'set_scroll_brightness', + # Scroll wheel controls + 'get_scroll_mode', 'set_scroll_mode', + 'get_scroll_acceleration', 'set_scroll_acceleration', + 'get_scroll_smart_reel', 'set_scroll_smart_reel', + # All LEDs (partial support) + 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', 'set_none_effect', + # Logo (partial support) + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', + # Scroll wheel (partial support) + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', + # Can set custom matrix effects + 'set_custom_effect', 'set_key_row', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/14676/14676-1-en-v1.png" + + DPI_MAX = 35000 + + +class RazerBasiliskV3Pro35KWireless(RazerBasiliskV3Pro35KWired): + """ + Class for the Razer Basilisk V3 Pro 35K (Wireless) + """ + + USB_PID = 0x00CD + + +class RazerBasiliskV3_35K(__RazerDevice): + """ + Class for the Razer Basilisk V3 35K + """ + + EVENT_FILE_REGEX = re.compile(r'.*Razer_Basilisk_V3_35K-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00CB + HAS_MATRIX = True + MATRIX_DIMS = [1, 13] + METHODS = ['get_device_type_mouse', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_brightness', 'set_brightness', + 'get_logo_brightness', 'set_logo_brightness', + 'get_scroll_brightness', 'set_scroll_brightness', + # Scroll wheel controls + 'get_scroll_mode', 'set_scroll_mode', + 'get_scroll_acceleration', 'set_scroll_acceleration', + 'get_scroll_smart_reel', 'set_scroll_smart_reel', + # All LEDs (partial support) + 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', 'set_none_effect', + # Logo (partial support) + 'set_logo_wave', 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', + # Scroll wheel (partial support) + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', + # Can set custom matrix effects + 'set_custom_effect', 'set_key_row'] + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/he4/h63/9822107926558/basilisk-v3-35k-2-500x500.png" + + DPI_MAX = 35000 + + +class RazerHyperPollingWirelessDongle(__RazerDevice): + """ + Class for the Razer HyperPolling Wireless Dongle + """ + + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_HyperPolling_Wireless_Dongle-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00B3 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + 'set_hyperpolling_wireless_dongle_indicator_led_mode', 'set_hyperpolling_wireless_dongle_pair', 'set_hyperpolling_wireless_dongle_unpair'] + + POLL_RATES = [125, 500, 1000, 2000, 4000, 8000] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6141/6141-1-en-v1.png" # HyperPolling Wireless Dongle + + # TODO: After pairing, should find a way to use the image of the mouse instead of the dongle + # DEVICE_IMAGE_DAV3PRO = "https://dl.razerzone.com/src/6130/6130-1-en-v2.png" # DeathAdder V3 Pro + # DEVICE_IMAGE_VIPERV2PRO = "https://dl.razerzone.com/src/6048-1-en-v10.png" # Viper V2 Pro + + DPI_MAX = 30000 + + +class RazerProClickMiniReceiver(__RazerDevice): + """ + Class for the Razer Pro Click Mini (Receiver) + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_ProClickM-if0(1|2)-event-kbd') + USB_VID = 0x1532 + USB_PID = 0x009A + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'get_idle_time', 'set_idle_time', + 'get_battery', 'is_charging', + 'get_low_battery_threshold', 'set_low_battery_threshold'] + DEVICE_IMAGE = "https://dl.razerzone.com/src/5763/5763-1-en-v1.png" + + DPI_MAX = 12000 + + POLL_RATES = [125, 500, 1000] + + +class RazerDeathAdderV2Lite(__RazerDevice): + """ + Class for the Razer DeathAdder V2 Lite + """ + EVENT_FILE_REGEX = re.compile(r'.*Razer_DeathAdder_V2_Lite-if0(1|2)-event-kbd') + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_logo_brightness', 'set_logo_brightness', + # Logo + 'set_logo_static', 'set_logo_spectrum', 'set_logo_none', 'set_logo_reactive', + 'set_logo_breath_random', 'set_logo_breath_single', 'set_logo_breath_dual', + # Custom frame + 'set_custom_effect', 'set_key_row'] + + USB_VID = 0x1532 + USB_PID = 0x00A1 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1692/deathadder-v2-mini.png" + + DPI_MAX = 8500 + + +class RazerCobra(__RazerDevice): + """ + Class for the Razer Cobra + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Cobra-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00A3 + METHODS = ['get_device_type_mouse', + 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + # Logo + 'get_logo_brightness', 'set_logo_brightness', + 'set_logo_breath_random', 'set_logo_breath_dual', 'set_logo_breath_single', + 'set_logo_reactive', 'set_logo_spectrum', 'set_logo_static', 'set_logo_none'] + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container/h54/h60/9591466950686/cobra-500x500.png" + + POLL_RATES = [125, 500, 1000] + DPI_MAX = 8500 + + +class RazerNagaV2HyperSpeedReceiver(__RazerDevice): + """ + Class for the Razer Naga V2 HyperSpeed (Receiver) + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Naga_V2_HyperSpeed_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00B4 + HAS_MATRIX = False + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://hybrismediaprod.blob.core.windows.net/sys-master-phoenix-images-container%2Fh4c%2Fh44%2F9451887460382%2Fnaga-v2-hyperspeed-500x500.png" + + DPI_MAX = 30000 + + +class RazerViperV3HyperSpeed(__RazerDevice): + """ + Class for the Razer Viper V3 HyperSpeed + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Viper_V3_HyperSpeed_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00B8 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/13432/13432-1-en-v3.png" + + DPI_MAX = 30000 + + +class RazerBasiliskV3XHyperSpeed(__RazerDevice): + """ + Class for the Razer Basilisk V3 X HyperSpeed + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Basilisk_V3_X_HyperSpeed_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00B9 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold', + # Scroll wheel + 'get_scroll_brightness', 'set_scroll_brightness', + 'set_scroll_wave', 'set_scroll_static', 'set_scroll_spectrum', 'set_scroll_none', 'set_scroll_reactive', 'set_scroll_breath_random', 'set_scroll_breath_single', 'set_scroll_breath_dual'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/9766/9766-1-en-v1.png" + DRIVER_MODE = True + + DPI_MAX = 18000 + + +class RazerViperV3ProWired(__RazerDevice): + """ + Class for the Razer Viper V3 Pro (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Viper_V3_Pro-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00C0 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/14044/14044-1-en-v1.png" + + POLL_RATES = [125, 500, 1000] + DPI_MAX = 35000 + + +class RazerViperV3ProWireless(RazerViperV3ProWired): + """ + Class for the Razer Viper V3 Pro (Wireless) + """ + + USB_PID = 0x00C1 + + METHODS = RazerViperV3ProWired.METHODS + ['set_hyperpolling_wireless_dongle_indicator_led_mode'] + + POLL_RATES = [125, 500, 1000, 2000, 4000, 8000] + + +class RazerDeathAdderV3HyperSpeedWired(__RazerDevice): + """ + Class for the Razer DeathAdder V3 HyperSpeed (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_DeathAdder_V3_HyperSpeed_000000000000-if0(1|2)-event-kbd') + + USB_VID = 0x1532 + USB_PID = 0x00C4 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', + # Battery + 'get_battery', 'is_charging', 'get_idle_time', 'set_idle_time', 'get_low_battery_threshold', 'set_low_battery_threshold'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src/6124/6124-1-en-v2.png" + + DPI_MAX = 26000 + + +class RazerDeathAdderV3HyperSpeedWireless(RazerDeathAdderV3HyperSpeedWired): + """ + Class for the Razer DeathAdder V3 HyperSpeed (Wireless) + """ + + USB_PID = 0x00C5 + + +class RazerProClickV2VerticalEditionWired(__RazerDevice): + """ + Class for the Razer Pro Click V2 Vertical Edition (Wired) + """ + EVENT_FILE_REGEX = re.compile(r'.*usb-Razer_Razer_Pro_Click_V2_Vertical_Edition-if0(1|2)-event-kbd') + USB_VID = 0x1532 + USB_PID = 0x00C7 + METHODS = ['get_device_type_mouse', 'max_dpi', 'get_dpi_xy', 'set_dpi_xy', + 'get_dpi_stages', 'set_dpi_stages', + 'get_poll_rate', 'set_poll_rate', 'get_supported_poll_rates', + 'get_idle_time', 'set_idle_time', + 'get_battery', 'is_charging', + 'get_low_battery_threshold', 'set_low_battery_threshold', + 'get_brightness', 'set_brightness', 'set_static_effect', 'set_wave_effect', 'set_spectrum_effect', 'set_none_effect'] + DEVICE_IMAGE = "https://dl.razerzone.com/src2/15010/15010-1-en-v1.png" + + DPI_MAX = 30000 + + POLL_RATES = [125, 250, 500, 1000] + + +class RazerProClickV2VerticalEditionWireless(RazerProClickV2VerticalEditionWired): + """ + Class for the Razer Pro Click V2 Vertical Edition (Wireless) + """ + USB_PID = 0x00C8 diff --git a/openrazer/daemon/openrazer_daemon/hardware/mouse_mat.py b/openrazer/daemon/openrazer_daemon/hardware/mouse_mat.py new file mode 100644 index 00000000..f15f201d --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/hardware/mouse_mat.py @@ -0,0 +1,126 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Mousemat class +""" +from openrazer_daemon.hardware.device_base import RazerDeviceBrightnessSuspend as __RazerDeviceBrightnessSuspend + + +class RazerFirefly(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Firefly (2013) + """ + USB_VID = 0x1532 + USB_PID = 0x0C00 + HAS_MATRIX = True + MATRIX_DIMS = [1, 15] + METHODS = ['get_device_type_mousemat', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_reactive_effect', 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/594/594_firefly_500x500.png" + + +class RazerFireflyV2(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Firefly V2 + """ + USB_VID = 0x1532 + USB_PID = 0x0C04 + HAS_MATRIX = True + MATRIX_DIMS = [1, 19] + METHODS = ['get_device_type_mousemat', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1594/1594_firefly_v2.png" + + +class RazerFireflyV2Pro(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Firefly V2 Pro + """ + USB_VID = 0x1532 + USB_PID = 0x0C08 + HAS_MATRIX = True + MATRIX_DIMS = [1, 17] + METHODS = ['get_device_type_mousemat', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://dl.razerzone.com/src2/14141/14141-1-en-v1.png" + + +class RazerFireflyHyperflux(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Firefly Hyperflux (2018) + """ + USB_VID = 0x1532 + USB_PID = 0x0068 + HAS_MATRIX = True + MATRIX_DIMS = [1, 17] + METHODS = ['get_device_type_mousemat', 'set_static_effect', 'set_spectrum_effect', 'set_key_row', 'set_custom_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/594/594_firefly_500x500.png" + + +class RazerGoliathus(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Goliathus (2018) + """ + USB_VID = 0x1532 + USB_PID = 0x0C01 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mousemat', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1394/1394_goliathus_chroma.png" + + +class RazerGoliathusExtended(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Goliathus Extended (2018) + """ + USB_VID = 0x1532 + USB_PID = 0x0C02 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mousemat', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1395/1395_goliathusextended.png" + + +class RazerGoliathusChroma3XL(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Goliathus Chroma 3XL + """ + USB_VID = 0x1532 + USB_PID = 0x0C06 + HAS_MATRIX = True + MATRIX_DIMS = [1, 1] + METHODS = ['get_device_type_mousemat', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://assets.razerzone.com/eeimages/support/products/1395/1395_goliathusextended.png" + + +class RazerStriderChroma(__RazerDeviceBrightnessSuspend): + """ + Class for the Razer Strider Chroma + """ + USB_VID = 0x1532 + USB_PID = 0x0C05 + HAS_MATRIX = True + MATRIX_DIMS = [1, 19] + METHODS = ['get_device_type_mousemat', 'set_wave_effect', 'set_static_effect', 'set_spectrum_effect', + 'set_none_effect', 'set_breath_random_effect', 'set_breath_single_effect', 'set_breath_dual_effect', + 'set_custom_effect', 'set_key_row', 'set_reactive_effect', 'trigger_reactive_effect'] + + DEVICE_IMAGE = "https://assets2.razerzone.com/images/pnx.assets/73158705dfbee8e688bab3c7ae99c6d3/razer-strider-chroma-extended-size-1920x700.webp" diff --git a/openrazer/daemon/openrazer_daemon/keyboard.py b/openrazer/daemon/openrazer_daemon/keyboard.py new file mode 100644 index 00000000..12931102 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/keyboard.py @@ -0,0 +1,596 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Module to handle custom colours +""" + +import struct +import subprocess + + +KEY_MAPPING = { + # Row 0 + 'M6': (0, 0), 'ESC': (0, 1), 'F1': (0, 3), 'F2': (0, 4), 'F3': (0, 5), 'F4': (0, 6), 'F5': (0, 7), 'F6': (0, 8), 'F7': (0, 9), 'F8': (0, 10), 'F9': (0, 11), 'F10': (0, 12), 'F11': (0, 13), 'F12': (0, 14), 'PRTSCR': (0, 15), 'SCRLK': (0, 16), 'PAUSE': (0, 17), 'LOGO': (0, 20), 'JP1': (0, 21), + # Row 1 + 'M1': (1, 0), 'BACKTICK': (1, 1), '1': (1, 2), '2': (1, 3), '3': (1, 4), '4': (1, 5), '5': (1, 6), '6': (1, 7), '7': (1, 8), '8': (1, 9), '9': (1, 10), '0': (1, 11), 'DASH': (1, 12), 'EQUALS': (1, 13), 'BACKSPACE': (1, 14), 'INS': (1, 15), 'HOME': (1, 16), 'PAGEUP': (1, 17), 'NUMLK': (1, 18), 'NPFORWARDSLASH': (1, 19), 'NPASTERISK': (1, 20), 'NPDASH': (1, 21), + # Row 2 + 'M2': (2, 0), 'TAB': (2, 1), 'Q': (2, 2), 'W': (2, 3), 'E': (2, 4), 'R': (2, 5), 'T': (2, 6), 'Y': (2, 7), 'U': (2, 8), 'I': (2, 9), 'O': (2, 10), 'P': (2, 11), 'LEFTSQUAREBRACKET': (2, 12), 'RIGHTSQUAREBRACKET': (2, 13), 'DELETE': (2, 15), 'END': (2, 16), 'PAGEDOWN': (2, 17), 'NP7': (2, 18), 'NP8': (2, 19), 'NP9': (2, 20), 'NPPLUS': (2, 21), + # Row 3 + 'M3': (3, 0), 'CAPSLK': (3, 1), 'A': (3, 2), 'S': (3, 3), 'D': (3, 4), 'F': (3, 5), 'G': (3, 6), 'H': (3, 7), 'J': (3, 8), 'K': (3, 9), 'L': (3, 10), 'SEMICOLON': (3, 11), 'APOSTROPHE': (3, 12), 'POUNDSIGN': (3, 13), 'RETURN': (3, 14), 'NP4': (3, 18), 'NP5': (3, 19), 'NP6': (3, 20), + # Row 4 + 'M4': (4, 0), 'LEFTSHIFT': (4, 1), 'BACKSLASH': (4, 2), 'Z': (4, 3), 'X': (4, 4), 'C': (4, 5), 'V': (4, 6), 'B': (4, 7), 'N': (4, 8), 'M': (4, 9), 'COMMA': (4, 10), 'PERIOD': (4, 11), 'FORWARDSLASH': (4, 12), 'JP2': (4, 13), 'RIGHTSHIFT': (4, 14), 'UPARROW': (4, 16), 'NP1': (4, 18), 'NP2': (4, 19), 'NP3': (4, 20), 'ENTER': (4, 21), + # Row 5 + 'M5': (5, 0), 'LEFTCTRL': (5, 1), 'SUPER': (5, 2), 'LEFTALT': (5, 3), 'SPACE': (5, 7), 'RIGHTALT': (5, 11), 'FN': (5, 12), 'CTXMENU': (5, 13), 'RIGHTCTRL': (5, 14), 'LEFTARROW': (5, 15), 'DOWNARROW': (5, 16), 'RIGHTARROW': (5, 17), 'NP0': (5, 19), 'NPPERIOD': (5, 20), + + # Additional mappings + 'MACROMODE': (0, 11), 'GAMEMODE': (0, 12), 'MUTE': (0, 3), 'VOL_DOWN': (0, 4), 'VOL_UP': (0, 5), 'MEDIA_BACK': (0, 7), 'MEDIA_PLAY': (0, 8), 'MEDIA_FORWARD': (0, 9), 'BRIGHTNESSDOWN': (0, 13), 'BRIGHTNESSUP': (0, 14) +} + + +# 0 1 2 3 4 5 6 7 +# ------------------------------------ +# 0 | 1 2 3 4 5 UP +# 1 | 6 7 8 9 10 LEFT RIGHT +# 2 | 11 12 13 14 15 TMB DOWN MS +# +# +# + +TARTARUS_KEY_MAPPING = { + '1': (0, 0), + '2': (0, 1), + '3': (0, 2), + '4': (0, 3), + '5': (0, 4), + 'UP': (0, 6), + + '6': (1, 0), + '7': (1, 1), + '8': (1, 2), + '9': (1, 3), + '10': (1, 4), + 'LEFT': (1, 5), + 'RIGHT': (1, 7), + + '11': (2, 0), + '12': (2, 1), + '13': (2, 2), + '14': (2, 3), + '15': (2, 4), + 'THUMB': (2, 5), + 'DOWN': (2, 6), + 'MODE_SWITCH': (2, 7) + +} + +# 0 1 2 3 4 5 6 7 +# ------------------------------------ +# 0 | 1 2 3 4 5 UP +# 1 | 6 7 8 9 10 LEFT RIGHT +# 2 | 11 12 13 14 15 TMB DOWN MS +# 3 | 16 17 18 19 20 +# + +ORBWEAVER_KEY_MAPPING = { + '1': (0, 0), + '2': (0, 1), + '3': (0, 2), + '4': (0, 3), + '5': (0, 4), + 'UP': (0, 6), + + '6': (1, 0), + '7': (1, 1), + '8': (1, 2), + '9': (1, 3), + '10': (1, 4), + 'LEFT': (1, 5), + 'RIGHT': (1, 7), + + '11': (2, 0), + '12': (2, 1), + '13': (2, 2), + '14': (2, 3), + '15': (2, 4), + 'THUMB': (2, 5), + 'DOWN': (2, 6), + 'MODE_SWITCH': (2, 7), + + '16': (3, 0), + '17': (3, 1), + '18': (3, 2), + '19': (3, 3), + '20': (3, 4) +} + +# Naga hex buttons are normal 1-7 keys +# 0 1 2 3 4 +# -------------- +# 0 | 1 2 +# 1 | 4 3 +# 2 | 5 7 +# 3 | 6 +NAGA_HEX_V2_KEY_MAPPING = { + '1': (0, 1), '2': (0, 3), + '4': (1, 0), '3': (1, 4), + '5': (2, 1), '7': (2, 3), + '6': (3, 2) +} + +# +EVENT_MAPPING = { + 1: 'ESC', 2: '1', 3: '2', 4: '3', 5: '4', 6: '5', 7: '6', 8: '7', 9: '8', + 10: '9', 11: '0', 12: 'DASH', 13: 'EQUALS', 14: 'BACKSPACE', 15: 'TAB', 16: 'Q', 17: 'W', 18: 'E', 19: 'R', + 20: 'T', 21: 'Y', 22: 'U', 23: 'I', 24: 'O', 25: 'P', 26: 'LEFTSQUAREBRACKET', 27: 'RIGHTSQUAREBRACKET', 28: 'RETURN', 29: 'LEFTCTRL', + 30: 'A', 31: 'S', 32: 'D', 33: 'F', 34: 'G', 35: 'H', 36: 'J', 37: 'K', 38: 'L', 39: 'SEMICOLON', + 40: 'APOSTROPHE', 41: 'BACKTICK', 42: 'LEFTSHIFT', 43: 'POUNDSIGN', 44: 'Z', 45: 'X', 46: 'C', 47: 'V', 48: 'B', 49: 'N', + 50: 'M', 51: 'COMMA', 52: 'PERIOD', 53: 'FORWARDSLASH', 54: 'RIGHTSHIFT', 55: 'NPASTERISK', 56: 'LEFTALT', 57: 'SPACE', + 58: 'CAPSLK', 59: 'F1', + 60: 'F2', 61: 'F3', 62: 'F4', 63: 'F5', 64: 'F6', 65: 'F7', 66: 'F8', 67: 'F9', 68: 'F10', 69: 'NUMLK', + 70: 'SCRLK', 71: 'NP7', 72: 'NP8', 73: 'NP9', 74: 'NPDASH', 75: 'NP4', 76: 'NP5', 77: 'NP6', 78: 'NPPLUS', 79: 'NP1', + 80: 'NP2', 81: 'NP3', 82: 'NP0', 83: 'NPPERIOD', 86: 'BACKSLASH', 87: 'F11', 88: 'F12', + 96: 'ENTER', 97: 'RIGHTCTRL', 98: 'NPFORWARDSLASH', 99: 'PRTSCR', + 100: 'RIGHTALT', 102: 'HOME', 103: 'UPARROW', 104: 'PAGEUP', 105: 'LEFTARROW', 106: 'RIGHTARROW', 107: 'END', 108: 'DOWNARROW', 109: 'PAGEDOWN', 110: 'INS', + 111: 'DELETE', 113: 'MUTE', 114: 'VOL_DOWN', 115: 'VOL_UP', 119: 'PAUSE', + 125: 'SUPER', 127: 'CTXMENU', + 142: 'SLEEP', + 163: 'MEDIA_FORWARD', 164: 'MEDIA_PLAY', 165: 'MEDIA_BACK', + 183: 'M1', 184: 'M2', 185: 'M3', 186: 'M4', 187: 'M5', 188: 'M6', + 189: 'M7', 190: 'M8', 191: 'M9', 192: 'M10', 193: 'M11', 194: 'M12', + 0x2ad: 'MACROMODE', 0x2ac: 'GAMEMODE', 0x2ab: 'BRIGHTNESSDOWN', 0x2aa: 'BRIGHTNESSUP' +} + +TARTARUS_EVENT_MAPPING = { + 15: '1', + 16: '2', + 17: '3', + 18: '4', + 19: '5', + 58: '6', + 30: '7', + 31: '8', + 32: '9', + 33: '10', + 42: '11', + 44: '12', + 45: '13', + 46: '14', + 47: '15', + 56: 'MODE_SWITCH', + 57: 'THUMB', + 103: 'UP', + 105: 'LEFT', + 106: 'RIGHT', + 108: 'DOWN', +} + +ORBWEAVER_EVENT_MAPPING = { + 41: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 15: '6', + 16: '7', + 17: '8', + 18: '9', + 19: '10', + 58: '11', + 30: '12', + 31: '13', + 32: '14', + 33: '15', + 42: '16', + 44: '17', + 45: '18', + 46: '19', + 47: '20', + 56: 'MODE_SWITCH', + 57: 'THUMB', + 103: 'UP', + 105: 'LEFT', + 106: 'RIGHT', + 108: 'DOWN', +} + +NAGA_HEX_V2_EVENT_MAPPING = { + 2: '1', 3: '2', 4: '3', 5: '4', 6: '5', 7: '6', 8: '7' +} + +XTE_MAPPING = { + 'ESC': 'Escape', + 'DASH': 'minus', + 'EQUALS': 'equal', + 'BACKSPACE': 'BackSpace', + 'TAB': 'Tab', + 'LEFTSQUAREBRACKET': 'bracketleft', + 'RIGHTSQUAREBRACKET': 'bracketright', + 'RETURN': 'Return', + 'LEFTCTRL': 'Control_L', + 'SEMICOLON': 'semicolon', + 'APOSTROPHE': 'apostrophe', + 'BACKTICK': 'grave', + 'LEFTSHIFT': 'Shift_L', + 'POUNDSIGN': 'numbersign', + 'COMMA': 'comma', + 'PERIOD': 'period', + 'FORWARDSLASH': 'slash', + 'RIGHTSHIFT': 'Shift_R', + 'NPASTERISK': 'KP_Multiply', + 'LEFTALT': 'Alt_L', + 'SPACE': 'space', + 'CAPSLK': 'Caps_Lock', + 'NUMLK': 'Num_Lock', + 'SCRLK': 'Scroll_Lock', + 'PAUSE': 'Pause', + 'NP7': '7', + 'NP8': '8', + 'NP9': '9', + 'NPDASH': 'KP_Subtract', + 'NP4': '4', + 'NP5': '5', + 'NP6': '6', + 'NPPLUS': 'KP_Add', + 'NP1': '1', + 'NP2': '2', + 'NP3': '3', + 'NP0': '0', + 'PRTSCR': 'Print', + 'NPPERIOD': 'KP_Decimal', + 'BACKSLASH': 'backslash', + 'ENTER': 'Enter', + 'RIGHTCTRL': 'Control_r', + 'NPFORWARDSLASH': 'KP_Divide', + 'RIGHTALT': 'Alt_R', + 'HOME': 'Home', + 'UPARROW': 'Up', + 'PAGEUP': 'Page_Up', + 'LEFTARROW': 'Left', + 'RIGHTARROW': 'Right', + 'END': 'End', + 'DOWNARROW': 'Down', + 'PAGEDOWN': 'Page_Down', + 'INS': 'Insert', + 'DELETE': 'Delete', + 'SUPER': 'Super_L', + 'CTXMENU': 'Menu', + 'M1': 'XF86Tools', + 'M2': 'XF86Launch5', + 'M3': 'XF86Launch6', + 'M4': 'XF86Launch7', + 'M5': 'XF86Launch8', + 'M6': 'XF86Launch9', + 'FN': None, + 'GAMEMODE': None, + 'MACROMODE': None, +} + + +class KeyDoesNotExistError(Exception): + """ + Simple custom error + """ + pass + + +class NoBackupError(Exception): + pass + + +class RGB(object): + + @staticmethod + def clamp(value): + """ + Clamp a value to 0-255 + + :param value: Value to be clamped + :type value: integer or float + + :return: Integer in the range of 0-255 + :rtype: int + """ + result = int(value) + + if value > 255: + result = 255 + elif value < 0: + result = 0 + + return result + + def __init__(self, red=0, green=0, blue=0): + self._red = red + self._green = green + self._blue = blue + + @property + def red(self): + """ + Getter for red element + + :return: Red element + :rtype: int + """ + return self._red + + @red.setter + def red(self, value): + """ + Setter for red value + + :param value: Red value + :type value: int or float + """ + self._red = RGB.clamp(value) + + @property + def green(self): + """ + Getter for green element + + :return: Green element + :rtype: int + """ + return self._green + + @green.setter + def green(self, value): + """ + Setter for green value + + :param value: Green value + :type value: int or float + """ + self._green = RGB.clamp(value) + + @property + def blue(self): + """ + Getter for blue element + + :return: Blue element + :rtype: int + """ + return self._blue + + @blue.setter + def blue(self, value): + """ + Setter for blue value + + :param value: Blue value + :type value: int or float + """ + self._blue = RGB.clamp(value) + + def set(self, colour_tuple): + """ + Sets all the colours at once + + :param colour_tuple: Tuple of R,G,B elements + :type colour_tuple: tuple + """ + # Shortcut to clamp all parameters and assign to the 3 variables + self._red, self._green, self._blue = list(map(RGB.clamp, colour_tuple)) + + def get(self): + """ + Gets all the colours as a tuple + + :return: RGB tuple + :rtype: tuple + """ + return self._red, self._green, self._blue + + def __bytes__(self): + """ + Convert to bytes + + :return: Byte string + :rtype: bytearray + """ + return bytes((self._red, self._green, self._blue)) + + def __repr__(self): + """ + String representation + + :return: String + :rtype: str + """ + return "RGB Object (#{0:02X}{1:02X}{2:02X})".format(self._red, self._green, self._blue) + + +class KeyboardColour(object): + """ + Keyboard class which represents the colour state of the keyboard. + """ + + def __init__(self, rows, columns): + self.rows = rows + self.columns = columns + + # Two-dimensional array to hold color data + self.colors = [] + + # Backup object (currently not used) + self.backup = None + + # Initialize array with empty values + self.reset_rows() + + def backup_configuration(self): + """ + Backs up the current configuration + """ + self.backup = KeyboardColour(self.rows, self.columns) + self.backup.get_from_total_binary(self.get_total_binary()) + + def restore_configuration(self): + """ + Restores the previous configuration + """ + if self.backup is None: + raise NoBackupError() + + self.colors = self.backup.colors + self.backup = None + + def get_rows_raw(self): + """ + Gets the raw representation of the rows + + :return: Rows + :rtype: list + """ + return self.colors + + def reset_rows(self): + """ + Reset the rows of the keyboard + """ + self.colors.clear() + + for row in range(0, self.rows): + # Create 22 rgb values + self.colors.append([RGB() for _ in range(0, self.columns)]) + + def set_key_colour(self, row, col, colour): + """ + Set the colour of a key + + :param row: Row ID + :type row: int + + :param col: Column ID + :type col: int + + :param colour: Colour to set + :type colour: tuple + + :raises KeyDoesNotExistError: If given key does not exist + """ + self.colors[row][col].set(colour) + + def get_key_colour(self, key): + """ + Get the colour of a key + + :param key: Key to set the colour of + :type key: str + + :raises KeyDoesNotExistError: If given key does not exist + """ + if key not in KEY_MAPPING: + raise KeyDoesNotExistError("The key \"{0}\" does not exist".format(key)) + + row_id, col_id = KEY_MAPPING[key] + return self.colors[row_id][col_id].get() + + def reset_key(self, row, col): + """ + Reset the colour of a key + + :param row: Row ID + :type row: int + + :param col: Column ID + :type col: int + + :raises KeyDoesNotExistError: If given key does not exist + """ + self.colors[row][col].set((0, 0, 0)) + + def get_row_binary(self, row_id): + """ + Gets the binary payload for a given row + + :param row_id: Row ID + :type row_id: int + + :return: Byte string of 67 bytes, Row ID byte then 22 RGB bytes + :rtype: bytearray + """ + assert isinstance(row_id, int), "Row ID is not an int" + + payload = bytes([row_id, 0x00, len(self.colors[row_id]) - 1]) + + for rgb in self.colors[row_id]: + payload += bytes(rgb) + + return payload + + def get_total_binary(self): + """ + Gets the binary payload for the whole keyboard + + :return: Byte string of 6*67 bytes, (Row ID byte then 22 RGB bytes) * 6 + :rtype: bytearray + """ + payload = b'' + + for row in range(0, self.rows): + payload += self.get_row_binary(row) + + return payload + + def get_from_total_binary(self, binary_blob): + """ + Load in a binary blob which is the output from get_total_binary + + :param binary_blob: Binary blob + :type binary_blob: bytearray + """ + self.reset_rows() + + for row_id in range(0, self.rows): + binary_blob = binary_blob[1:] # Skip first byte + + for col_id, binary_rgb in enumerate([binary_blob[i:i + 3] for i in range(0, 66, 3)]): + rgb = struct.unpack('=BBB', binary_rgb) + self.colors[row_id][col_id].set(rgb) + + binary_blob = binary_blob[66:] # Skip the current row + + +def get_keyboard_layout(): + """ + Function to get the keyboard layout + + I can see this becoming an ugly mess as it'll need to support multiple keyboard layouts which have different names + on different systems + + :return: Keyboard layout + :rtype: str + """ + cmd = ['setxkbmap', '-query'] + output = subprocess.check_output(cmd) + + result = 'gb' + + if output: + output = output.decode('utf-8').splitlines() + layout = 'gb' + variant = '' + for line in output: + if line.startswith('layout'): + layout = line.split(':', 1)[1].strip() + if layout.find(',') > -1: + layout = layout.split(',')[0] + + elif line.startswith('variant'): + variant = line.split(':', 1)[1].strip().split(',')[0] + + if 'latin9' in variant: # Removes some rubbish from ubuntu + variant = 'latin9' + + if variant == '': + result = layout + else: + result = layout + '-' + variant + + # If the user has an international layout variant ignore that part + result = result.replace('-altgr-intl', '') + + return result diff --git a/openrazer/daemon/openrazer_daemon/misc/__init__.py b/openrazer/daemon/openrazer_daemon/misc/__init__.py new file mode 100644 index 00000000..315c06b6 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/__init__.py @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-or-later diff --git a/openrazer/daemon/openrazer_daemon/misc/autosave_persistence.py b/openrazer/daemon/openrazer_daemon/misc/autosave_persistence.py new file mode 100644 index 00000000..3b9af61c --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/autosave_persistence.py @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +A class that writes persistence data to disk when device state is updated. + +Due to the architecture of the daemon, it's not as simple to know when +something has changed, so for now, an interval will periodically check for +changes in memory and write them to disk. This also avoids excessive +writes when lots of variables change at once. + +This is essential because many desktop environments actually kill off +the daemon upon logout/shutdown, thereby persistence isn't retained across +sessions. + +A known issue is that this doesn't monitor DPI changes via hardware buttons, +so this won't be persisted until the state is updated via the API. +""" +import time + + +class PersistenceAutoSave(object): + def __init__(self, persistence, persistence_file, persistence_status, logger, interval, persistence_save_fn): + self.persistence = persistence + self.persistence_file = persistence_file + self.persistence_status = persistence_status + self.persistence_save_fn = persistence_save_fn + self.logger = logger + self.interval = interval + + def watch(self): + # Run indefinitely until process is terminated + while True: + time.sleep(self.interval) + + if self.persistence_status["changed"]: + self.logger.debug("State recently changed, writing to disk") + self.persistence_status["changed"] = False + self.persistence_save_fn(self.persistence_file) diff --git a/openrazer/daemon/openrazer_daemon/misc/battery_notifier.py b/openrazer/daemon/openrazer_daemon/misc/battery_notifier.py new file mode 100644 index 00000000..76f32e4e --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/battery_notifier.py @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +This will do until I can be bothered to create indicator applet to do battery level +""" +import logging +import threading +import datetime +import time +import subprocess + + +class BatteryNotifier(threading.Thread): + """ + Thread to notify about battery + """ + + def __init__(self, parent, device_id, device_name): + super().__init__() + self._logger = logging.getLogger('razer.device{0}.batterynotifier'.format(device_id)) + + self.event = threading.Event() + self.frequency = 0 + self.percent = 0 + + self._shutdown = False + self._device_name = device_name + + # Could save reference to parent but only need battery level function + self._get_battery_func = parent.getBattery + + self._last_notify_time = datetime.datetime(1970, 1, 1) + + @property + def shutdown(self): + """ + Get the shutdown flag + """ + return self._shutdown + + @shutdown.setter + def shutdown(self, value): + """ + Set the shutdown flag + + :param value: Shutdown + :type value: bool + """ + self._shutdown = value + + def show_notification(self, summary: str, message: str, icon: str) -> None: + try: + subprocess.run(["notify-send", "-a", "OpenRazer", "-i", icon, "-t", "4000", summary, message], + check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) + except subprocess.CalledProcessError as e: + self._logger.warning(f"Failed to show notification: {e.output.strip()}") + + def notify_battery(self): + now = datetime.datetime.now() + + if (now - self._last_notify_time).seconds > self.frequency: + battery_level = self._get_battery_func() + battery_percent = round(battery_level) + + # Sometimes due to various issues we don't get the percentage correctly. + # Just ignore them and don't show a bogus notification. + # See also: https://github.com/openrazer/openrazer/issues/2122 + if battery_level in (0.0, -1.0): + self._logger.debug("Got bogus battery value: {0}, ignoring.".format(battery_level)) + # Since we don't update _last_notify_time here we're going to retry very soon again. + # Sleep a bit so we don't spam the device with requests. + time.sleep(10) + return + + # Update the last notified time so that we alert in the configured frequency. + self._last_notify_time = now + + title = self._device_name + message = "Battery is {0}%".format(battery_percent) + icon = "battery-full" + + if battery_level <= 10.0: + message = "Battery is low ({0}%). Please charge your device".format(battery_percent) + icon = "battery-empty" + + elif battery_level <= 30.0: + icon = "battery-low" + + elif battery_level <= 70.0: + icon = "battery-good" + + elif battery_level == 100.0: + message = "Battery is fully charged ({0}%)".format(battery_percent) + + self._logger.debug("{0} Battery at {1}%".format(self._device_name, battery_percent)) + + if battery_level <= self.percent: + self.show_notification(summary=title, message=message, icon=icon) + + def run(self): + """ + Main thread function + """ + + while not self._shutdown: + if self.event.is_set() and self.frequency > 0: + self.notify_battery() + + time.sleep(0.1) + + self._logger.debug("Shutting down battery notifier") + + +class BatteryManager(object): + """ + Class which manages the overall process of notifing battery levels + """ + + def __init__(self, parent, device_number, device_name): + self._logger = logging.getLogger('razer.device{0}.batterymanager'.format(device_number)) + self._parent = parent + + self._battery_thread = BatteryNotifier(parent, device_number, device_name) + self._battery_thread.start() + + self._is_closed = False + + def close(self): + """ + Close the manager, stop ripple thread + """ + if not self._is_closed: + self._logger.debug("Closing Battery Manager") + self._is_closed = True + + self._battery_thread.shutdown = True + self._battery_thread.join(timeout=2) + if self._battery_thread.is_alive(): + self._logger.error("Could not stop BatteryNotify thread") + + def __del__(self): + self.close() + + @property + def active(self): + return self._battery_thread.event.is_set() + + @active.setter + def active(self, value): + if value: + self._battery_thread.event.set() + else: + self._battery_thread.event.clear() + + @property + def frequency(self): + return self._battery_thread.frequency + + @frequency.setter + def frequency(self, frequency): + self._battery_thread.frequency = frequency + + @property + def percent(self): + return self._battery_thread.percent + + @percent.setter + def percent(self, percent): + self._battery_thread.percent = percent diff --git a/openrazer/daemon/openrazer_daemon/misc/effect_sync.py b/openrazer/daemon/openrazer_daemon/misc/effect_sync.py new file mode 100644 index 00000000..8afeef11 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/effect_sync.py @@ -0,0 +1,329 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Class to manage syncing of effects +""" +import inspect +import logging + + +class EffectSync(object): + """ + Class which deals with receiving effect events from other devices + """ + + def __init__(self, parent, device_number): + self._logger = logging.getLogger('razer.device{0}.effect_sync'.format(device_number)) + self._parent = parent + self._parent.register_observer(self) + + def __del__(self): + self.close() + + def close(self): + self._parent.remove_observer(self) + + def notify(self, msg): + """ + Receive notificatons from the device (we only care about effects) + + :param msg: Notification + :type msg: tuple + """ + if not isinstance(msg, tuple): + self._logger.warning("Got msg that was not a tuple") + elif msg[0] == 'effect': + # We have a message directed at us + # MSG format + # 0 1 2 3 + # ('effect', Device, 'effectName', 'effectparams'...) + # Device is the device the msg originated from (could be parent device) + if msg[1] is not self._parent: + # Msg from another device + self.run_effect(msg[2], *msg[3:]) + + def run_effect(self, effect_name, *args): + """ + Run the specified effect with the given arguments + + :param effect_name: Name of the effect + :type effect_name: str + + :param args: Arguments for the specified effect + :type args: list + """ + # Disable notifications + self._parent.disable_notify = True + + try: + # Does parent have method + effect_func = getattr(self._parent, effect_name, None) + if effect_func is not None: + # We have method, does it have the correct num arguments + actual_args = self.get_num_arguments(effect_func) + if actual_args == len(args): + # method should be same + effect_func(*args) + else: + # Method same but wrong args, try alternatives + if effect_name == 'setStatic': + # Could be static from chroma to non chroma + if actual_args == 0: + # Chroma -> BW + effect_func() + else: + # BW -> Chroma + effect_func(0x0, 0xFF, 0x00) # Green + + else: + # setNone sets active to false and needs to be re-enabled for effects to show - maybe a bit inefficient + if not effect_name == 'setNone': + effect_func = getattr(self._parent, 'setScrollActive', None) + if effect_func is not None: + effect_func(True) + effect_func = getattr(self._parent, 'setLogoActive', None) + if effect_func is not None: + effect_func(True) + effect_func = getattr(self._parent, 'setLeftActive', None) + if effect_func is not None: + effect_func(True) + effect_func = getattr(self._parent, 'setRightActive', None) + if effect_func is not None: + effect_func(True) + effect_func = getattr(self._parent, 'setBacklightActive', None) + if effect_func is not None: + effect_func(True) + else: + effect_func = getattr(self._parent, 'setScrollNone', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setLogoNone', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setLeftNone', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setRightNone', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setBacklightNone', None) + if effect_func is not None: + effect_func() + + # The target device doesn't have these methods, use similar ones + + if effect_name == 'setPulsate': + # setPulsate doesn't provide a color but we need one, take green. + pargs = (0x00, 0xFF, 0x00) # Green + effect_func = getattr(self._parent, 'setBreathSingle', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setScrollBreathSingle', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setLogoBreathSingle', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setLeftBreathSingle', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setRightBreathSingle', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setScrollPulsate', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setLogoPulsate', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setBacklightPulsate', None) + if effect_func is not None: + effect_func(*pargs) + + elif effect_name == 'setSpectrum': + effect_func = getattr(self._parent, 'setScrollSpectrum', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setLogoSpectrum', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setLeftSpectrum', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setRightSpectrum', None) + if effect_func is not None: + effect_func() + effect_func = getattr(self._parent, 'setBacklightSpectrum', None) + if effect_func is not None: + effect_func() + + elif effect_name == 'setStatic': + effect_func = getattr(self._parent, 'setScrollStatic', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLogoStatic', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLeftStatic', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setRightStatic', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setBacklightStatic', None) + if effect_func is not None: + effect_func(*args) + + elif effect_name == 'setWave': + effect_func = getattr(self._parent, 'setScrollWave', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLogoWave', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLeftWave', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setRightWave', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setBacklightWave', None) + if effect_func is not None: + effect_func(*args) + + elif effect_name == 'setReactive': + effect_func = getattr(self._parent, 'setScrollReactive', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLogoReactive', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLeftReactive', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setRightReactive', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setBacklightReactive', None) + if effect_func is not None: + effect_func(*args) + + elif effect_name in ('setBreathRandom', 'setBreathSingle', 'setBreathDual', 'setBreathTriple'): + if effect_name in ('setBreathRandom', 'setBreathSingle'): + pargs = (0x00, 0xFF, 0x00) # Green + else: + pargs = args[0:3] # limit args to first 3, as setBreathDual gives 6 args and setBreathTriple gives 9 args + + if effect_name == 'setBreathRandom': + effect_func = getattr(self._parent, 'setPulsate', None) + if effect_func is not None: + # setPulsate doesn't take any argument + effect_func() + effect_func = getattr(self._parent, 'setScrollPulsate', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setLogoPulsate', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setBacklightPulsate', None) + if effect_func is not None: + effect_func(*pargs) + + effect_func = getattr(self._parent, 'setScrollBreathRandom', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLogoBreathRandom', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLeftBreathRandom', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setRightBreathRandom', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setBacklightBreathRandom', None) + if effect_func is not None: + effect_func(*args) + + if effect_name == 'setBreathSingle': + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setScrollPulsate', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setLogoPulsate', None) + if effect_func is not None: + effect_func(*pargs) + effect_func = getattr(self._parent, 'setBacklightPulsate', None) + if effect_func is not None: + effect_func(*pargs) + + effect_func = getattr(self._parent, 'setScrollBreathSingle', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLogoBreathSingle', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLeftBreathSingle', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setRightBreathSingle', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setBacklightBreathSingle', None) + if effect_func is not None: + effect_func(*args) + + if effect_name == 'setBreathDual': + effect_func = getattr(self._parent, 'setScrollBreathDual', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLogoBreathDual', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLeftBreathDual', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setRightBreathDual', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setBacklightBreathDual', None) + if effect_func is not None: + effect_func(*args) + + elif effect_name == 'setBrightness': + effect_func = getattr(self._parent, 'setScrollBrightness', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLogoBrightness', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setLeftBrightness', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setRightBrightness', None) + if effect_func is not None: + effect_func(*args) + effect_func = getattr(self._parent, 'setBacklightBrightness', None) + if effect_func is not None: + effect_func(*args) + + except Exception as err: + self._logger.exception("Caught exception trying to sync effects.", exc_info=err) + + # Re-enable notifications + self._parent.disable_notify = False + + @staticmethod + def get_num_arguments(func): + """ + Get number of arguments in a function + + :param func: Function + :type func: callable + + :return: Number of arguments + :rtype: int + """ + func_sig = inspect.signature(func) + return len(func_sig.parameters) diff --git a/openrazer/daemon/openrazer_daemon/misc/key_event_management.py b/openrazer/daemon/openrazer_daemon/misc/key_event_management.py new file mode 100644 index 00000000..fa11b649 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/key_event_management.py @@ -0,0 +1,748 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Receives events from /dev/input/by-id/somedevice + +Events are 24 bytes long and are emitted from a character device in 24 byte chunks. +As the keyboards have "2" keyboard interfaces we need to listen on both of them in case some n00b +switches to game mode. + +Each event is in the format of +* signed int of seconds +* signed int of microseconds +* unsigned short of event type +* unsigned short code +* signed int value +""" +import datetime +import fcntl +import json +import logging +import os +import random +import select +import struct +import threading +import time + +# pylint: disable=import-error +from openrazer_daemon.keyboard import KEY_MAPPING, TARTARUS_KEY_MAPPING, EVENT_MAPPING, TARTARUS_EVENT_MAPPING, NAGA_HEX_V2_EVENT_MAPPING, NAGA_HEX_V2_KEY_MAPPING, ORBWEAVER_EVENT_MAPPING, ORBWEAVER_KEY_MAPPING +from .macro import MacroKey, MacroRunner, macro_dict_to_obj + +EVENT_FORMAT = '@llHHI' +EVENT_SIZE = struct.calcsize(EVENT_FORMAT) + +EPOLL_TIMEOUT = 0.01 +SPIN_SLEEP = 0.01 + +EVIOCGRAB = 0x40044590 + +COLOUR_CHOICES = ( + (255, 0, 0), # Red + (0, 255, 0), # Green + (0, 0, 255), # Blue + (255, 255, 0), # Yellow + (0, 255, 255), # Cyan + (255, 0, 255), # Magenta +) + + +def random_colour_picker(last_choice, iterable): + """ + Chose a random choice but not the last one + + :param last_choice: Last choice + :type last_choice: object + + :param iterable: Iterable object + :type iterable: iterable + + :return: Choice + :rtype: object + """ + result = random.choice(iterable) + while result == last_choice: + result = random.choice(iterable) + return result + + +class KeyWatcher(threading.Thread): + """ + Thread to watch keyboard event files and return keypresses + """ + @staticmethod + def parse_event_record(data): + """ + Parse Input event record + + :param data: Binary data + :type data: bytes + + :return: Tuple of event time, key_action, key_code + :rtype: tuple + """ + # Event Seconds, Event Microseconds, Event Type, Event Code, Event Value + ev_sec, ev_usec, ev_type, ev_code, ev_value = struct.unpack(EVENT_FORMAT, data) + + if ev_type != 0x01: # input-event-codes.h EV_KEY 0x01 + return None, None, None + + if ev_value == 0: + key_action = 'release' + elif ev_value == 1: + key_action = 'press' + elif ev_value == 2: + key_action = 'autorepeat' + else: + key_action = 'unknown' + + seconds = ev_sec + (ev_usec * 0.000001) + date = datetime.datetime.fromtimestamp(seconds) + + result = (date, key_action, ev_code) + + if ev_type == ev_code == ev_value == 0: + return None, None, None + + return result + + def __init__(self, device_id, event_files, parent, use_epoll=True): + super().__init__() + + self._logger = logging.getLogger('razer.device{0}.keywatcher'.format(device_id)) + self._event_files = event_files + self._shutdown = False + self._use_epoll = use_epoll + self._parent = parent + + self.open_event_files = [open(event_file, 'rb') for event_file in self._event_files] + # Set open files to non blocking mode + for event_file in self.open_event_files: + flags = fcntl.fcntl(event_file.fileno(), fcntl.F_GETFL) + fcntl.fcntl(event_file.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK) + + def run(self): + """ + Main event loop + """ + # Create dict of Event File Descriptor: Event File Object + event_file_map = {event_file.fileno(): event_file for event_file in self.open_event_files} + + # Create epoll object + poll_object = select.epoll() + + # Register files with select + for event_fd in event_file_map.keys(): + poll_object.register(event_fd, select.EPOLLIN | select.EPOLLPRI) + + # Loop + while not self._shutdown: + # epoll is nice but it wasn't getting events properly :( + + try: # Cheap hack until i merged new code + if self._use_epoll: + self._poll_epoll(poll_object, event_file_map) + else: + self._poll_read() + except (IOError, OSError): # Basically if there's an error, most likely device has been removed then it'll get deleted properly + pass + + time.sleep(SPIN_SLEEP) + + # Unbind files and close them + for event_fd, event_file in event_file_map.items(): + poll_object.unregister(event_fd) + event_file.close() + + poll_object.close() + + def _poll_epoll(self, poll_object, event_file_map): + events = poll_object.poll(EPOLL_TIMEOUT) + + if len(events) != 0: + # pylint: disable=unused-variable + for event_fd, mask in events: + while True: + key_data = event_file_map[event_fd].read(EVENT_SIZE) + if not key_data: + break + + date, key_action, key_code = self.parse_event_record(key_data) + + # Skip if date, key_action and key_code is none as that's a spacer record + if date is None: + continue + + # Now if key is pressed then we record + self._parent.key_action(date, key_code, key_action) + + def _poll_read(self): + for event_file in self.open_event_files: + + key_data = event_file.read(EVENT_SIZE) + + if key_data is None: + continue + + date, key_action, key_code = self.parse_event_record(key_data) + + # Skip if date, key_action and key_code is none as that's a spacer record + if date is None: + continue + + # Now if key is pressed then we record + self._parent.key_action(date, key_code, key_action) + + @property + def shutdown(self): + """ + Thread shutdown condition + + :return: Shutdown condition + :rtype: bool + """ + return self._shutdown + + @shutdown.setter + def shutdown(self, value): + """ + Set thread shutdown condition + + :param value: Boolean, normally only True would be used + :type value: str + """ + self._shutdown = value + + +class KeyboardKeyManager(object): + """ + Key management class. + + This class deals with anything to do with keypresses. Currently it does: + * Receiving keypresses from the KeyWatcher + * Logic to deal with GameMode shortcut not working when macro's not enabled + * Logic to deal with recording on the fly macros and replaying them + + It will be used to store keypresses in a list (for at most 2 seconds) if enabled for the ripple effect, when I + get round to making the effect. + """ + KEY_MAP = KEY_MAPPING + EVENT_MAP = EVENT_MAPPING + + # pylint: disable=too-many-instance-attributes + def __init__(self, device_id, event_files, parent, use_epoll=False, testing=False, should_grab_event_files=False): + + self._device_id = device_id + self._logger = logging.getLogger('razer.device{0}.keymanager'.format(device_id)) + self._parent = parent + self._parent.register_observer(self) + self._testing = testing + + self._event_files = event_files + self._access_lock = threading.Lock() + self._keywatcher = KeyWatcher(device_id, event_files, self, use_epoll=use_epoll) + self._open_event_files = self._keywatcher.open_event_files + + if len(event_files) > 0: + self._logger.debug("Starting KeyWatcher") + self._keywatcher.start() + else: + self._logger.warning("No event files for KeyWatcher") + + self._recording_macro = False + self._macros = {} + + self._current_macro_bind_key = None + self._current_macro_combo = [] + + self._threads = set() + self._clean_counter = 0 + + self._temp_key_store_active = False + self._temp_key_store = [] + self._temp_expire_time = datetime.timedelta(seconds=2) + + self._last_colour_choice = None + + self._should_grab_event_files = should_grab_event_files + self._event_files_locked = False + + if self._should_grab_event_files: + self.grab_event_files(True) + + @property + def temp_key_store(self): + """ + Get the temporary key store + + :return: List of keys + :rtype: list + """ + # Locking so it doesn't mutate whilst copying + self._access_lock.acquire() + now = datetime.datetime.now() + + # Remove expired keys from store + try: + # Get date and if its less than now its expired + while self._temp_key_store[0][0] < now: + self._temp_key_store.pop(0) + except IndexError: + pass + + # Creating a copy as then it doesn't mutate whilst iterating + result = self._temp_key_store[:] + self._access_lock.release() + return result + + @property + def temp_key_store_state(self): + """ + Get the state of the temporary key store + + :return: Active state + :rtype: bool + """ + return self._temp_key_store_active + + @temp_key_store_state.setter + def temp_key_store_state(self, value): + """ + Set the state of the temporary key store + + :param value: Active state + :type value: bool + """ + self._temp_key_store_active = value + + def grab_event_files(self, grab): + """ + Grab the event files exclusively + + :param grab: True to grab, False to release + :type grab: bool + """ + if not self._testing: + for event_file in self._open_event_files: + fcntl.ioctl(event_file.fileno(), EVIOCGRAB, int(grab)) + self._event_files_locked = grab + + def key_action(self, event_time, key_id, key_press='press'): + """ + Process a key press event + + Ok an attempt to explain the logic + * The function sets a value _fn_down depending on the state of FN. + * Adds keypress and release events to a macro list if recording a macro. + * Pressing FN+F9 starts recording a macro, then selecting any key marks that as a macro key, + then it will record keys, then pressing FN+F9 will save macro. + * Pressing any macro key will run macro. + * Pressing FN+F10 will toggle game mode. + :param event_time: Time event occurred + :type event_time: datetime.datetime + + :param key_id: Key Event ID + :type key_id: int + + :param key_press: Can either be press, release, autorepeat + :type key_press: bool + """ + # Disable pylints complaining for this part, #PerformanceOverNeatness + # pylint: disable=too-many-branches,too-many-statements + + # Get event files if they arnt locked #nasty hack + if not self._event_files_locked and self._should_grab_event_files: + self.grab_event_files(True) + + if key_press == 'autorepeat': # TODO not done right yet + # If its brightness then convert autorepeat to key presses + # Brightness keys are defined in keyboard.py and razerkbd_driver.c + if key_id in (0x2ab, 0x2aa): + key_press = 'press' + else: + # Quit out early + return + + now = datetime.datetime.now() + + # Remove expired keys from store + try: + # Get date and if its less than now its expired + while self._temp_key_store[0][0] < now: + self._temp_key_store.pop(0) + except IndexError: + pass + + # Clean up any threads + if self._clean_counter > 20 and len(self._threads) > 0: + self._clean_counter = 0 + self.clean_macro_threads() + + try: + # Convert event ID to key name + key_name = self.EVENT_MAP[key_id] + + # self._logger.info("Got key: {0}, state: {1}".format(key_name, 'DOWN' if key_press else 'UP')) + + # Key release + if key_press == 'release': + if self._recording_macro: + # Skip as don't care about releasing macro bind key + if key_name not in (self._current_macro_bind_key, 'MACROMODE'): + # Record key release events + self._current_macro_combo.append((event_time, key_name, 'UP')) + + else: + # Key press + + if self._temp_key_store_active: + colour = random_colour_picker(self._last_colour_choice, COLOUR_CHOICES) + self._last_colour_choice = colour + self._temp_key_store.append((now + self._temp_expire_time, self.KEY_MAP[key_name], colour)) + + # Macro FN+F9 logic + if key_name == 'MACROMODE': + self._logger.info("Got macro combo") + + if not self._recording_macro: + # Starting to record macro + self._recording_macro = True + self._current_macro_bind_key = None + self._current_macro_combo = [] + + self._parent.setMacroEffect(0x01) + self._parent.setMacroMode(True) + + else: + self._logger.debug("Finished recording macro") + # Finish recording macro + if self._current_macro_bind_key is not None: + if len(self._current_macro_combo) > 0: + self.add_kb_macro() + else: + # Clear macro + self.dbus_delete_macro(self._current_macro_bind_key) + self._recording_macro = False + self._parent.setMacroEffect(0x00) + self._parent.setMacroMode(False) + # Sets up game mode as when enabling macro keys it stops the key working + elif key_name == 'GAMEMODE': + self._logger.info("Got game mode combo") + + game_mode = self._parent.getGameMode() + self._parent.setGameMode(not game_mode) + + # Brightness logic + elif key_name == 'BRIGHTNESSDOWN': + # Get brightness value + current_brightness = self._parent.method_args.get('brightness', None) + if current_brightness is None: + current_brightness = self._parent.getBrightness() + + if current_brightness > 0: + current_brightness -= 10 + if current_brightness < 0: + current_brightness = 0 + + self._parent.setBrightness(current_brightness) + # self._parent.method_args['brightness'] = current_brightness + elif key_name == 'BRIGHTNESSUP': + # Get brightness value + current_brightness = self._parent.method_args.get('brightness', None) + if current_brightness is None: + current_brightness = self._parent.getBrightness() + + if current_brightness < 100: + current_brightness += 10 + if current_brightness > 100: + current_brightness = 100 + + self._parent.setBrightness(current_brightness) + # self._parent.method_args['brightness'] = current_brightness + + elif self._recording_macro: + + if self._current_macro_bind_key is None: + # Restrict macro bind keys to M1-M5 + if key_name not in ('M1', 'M2', 'M3', 'M4', 'M5', 'M6'): + self._logger.warning("Macros are only for M1-M6 for now.") + self._recording_macro = False + self._parent.setMacroMode(False) + else: + self._current_macro_bind_key = key_name + self._parent.setMacroEffect(0x00) + # Don't want no recursion, cancel macro, don't let one call macro in a macro + elif key_name == self._current_macro_bind_key: + self._logger.warning("Skipping macro assignment as would cause recursion") + self._recording_macro = False + self._parent.setMacroMode(False) + # Anything else just record it + else: + self._current_macro_combo.append((event_time, key_name, 'DOWN')) + # Not recording anything so if a macro key is pressed then run + else: + # If key has a macro, play it + if key_name in self._macros: + self.play_macro(key_name) + + except KeyError as err: + self._logger.exception("Got key error. Couldn't convert event to key name", exc_info=err) + + def add_kb_macro(self): + """ + Tidy up the recorded macro and add it to the store + + Goes through the macro and generated relative delays between key events + """ + new_macro = [] + + start_time = self._current_macro_combo[0][0] + for event_time, key, state in self._current_macro_combo: + delay = (event_time - start_time).microseconds + start_time = event_time + new_macro.append(MacroKey(key, delay, state)) + + self._macros[self._current_macro_bind_key] = new_macro + + def clean_macro_threads(self): + """ + Threadless-threadpool + + Goes though the threads (macro play jobs) and removed the threads if they have finished. + #SetMagic + """ + self._logger.debug("Cleaning up macro threads") + to_remove = set() + + for macro_thread in self._threads: + macro_thread.join(timeout=0.05) + if not macro_thread.is_alive(): + to_remove.add(macro_thread) + + self._threads -= to_remove + + def play_macro(self, macro_key): + """ + Play macro for a given key + + Launches a thread and adds it to the pool + :param macro_key: Macro Key + :type macro_key: str + """ + self._logger.info("Running Macro %s:%s", macro_key, str(self._macros[macro_key])) + macro_thread = MacroRunner(self._device_id, macro_key, self._macros[macro_key]) + macro_thread.start() + self._threads.add(macro_thread) + + # Methods to be used with DBus + def dbus_delete_macro(self, key_name): + """ + Delete a macro from a key + + :param key_name: Key Name + :type key_name: str + """ + try: + del self._macros[key_name] + except KeyError: + pass + + def dbus_get_macros(self): + """ + Get macros in JSON format + + Returns a JSON blob of all active macros in the format of + {BIND_KEY: [MACRO_DICT...]} + + MACRO_DICT is a dict representation of an action that can be performed. The dict will have a + type key which determines what type of action it will perform. + For example there are key press macros, URL opening macros, Script running macros etc... + :return: JSON of macros + :rtype: str + """ + result_dict = {} + for macro_key, macro_combo in self._macros.items(): + str_combo = [value.to_dict() for value in macro_combo] + result_dict[macro_key] = str_combo + + return json.dumps(result_dict) + + def dbus_add_macro(self, macro_key, macro_json): + """ + Add macro from JSON + + The macro_json will be a list of macro objects which is then converted into JSON + :param macro_key: Macro bind key + :type macro_key: str + + :param macro_json: Macro JSON + :type macro_json: str + """ + macro_list = [macro_dict_to_obj(macro_object_dict) for macro_object_dict in json.loads(macro_json)] + self._macros[macro_key] = macro_list + + def close(self): + """ + Cleanup function + """ + if self._keywatcher.is_alive(): + self._parent.remove_observer(self) + + self._logger.debug("Stopping key manager") + self._keywatcher.shutdown = True + self._keywatcher.join(timeout=2) + if self._keywatcher.is_alive(): + self._logger.error("Could not stop KeyWatcher thread") + + def __del__(self): + self.close() + + def notify(self, msg): + """ + Receive notificatons from the device (we only care about effects) + + :param msg: Notification + :type msg: tuple + """ + if not isinstance(msg, tuple): + self._logger.warning("Got msg that was not a tuple") + elif msg[0] == 'effect': + # We have a message directed at us + # MSG format + # 0 1 2 3 + # ('effect', Device, 'effectName', 'effectparams'...) + # Device is the device the msg originated from (could be parent device) + if msg[2] != 'setRipple': + # If we are not doing ripple effect then disable the storing of keys + # self.temp_key_store_state = False + pass + + +class NagaHexV2KeyManager(KeyboardKeyManager): + KEY_MAP = NAGA_HEX_V2_KEY_MAPPING + EVENT_MAP = NAGA_HEX_V2_EVENT_MAPPING + + +class GamepadKeyManager(KeyboardKeyManager): + GAMEPAD_EVENT_MAPPING = TARTARUS_EVENT_MAPPING + GAMEPAD_KEY_MAPPING = TARTARUS_KEY_MAPPING + + def __init__(self, device_id, event_files, parent, use_epoll=True, testing=False): + super().__init__(device_id, event_files, parent, use_epoll, testing=testing) + + self._mode_modifier = False + self._mode_modifier_combo = [] + self._mode_modifier_key_down = False + + def key_action(self, event_time, key_id, key_press=True): + """ + Process a key press event + + Ok an attempt to explain the logic + * The function sets a value _fn_down depending on the state of FN. + * Adds keypress and release events to a macro list if recording a macro. + * Pressing FN+F9 starts recording a macro, then selecting any key marks that as a macro key, + then it will record keys, then pressing FN+F9 will save macro. + * Pressing any macro key will run macro. + * Pressing FN+F10 will toggle game mode. + :param event_time: Time event occurred + :type event_time: datetime.datetime + + :param key_id: Key Event ID + :type key_id: int + + :param key_press: If true then its a press, else its a release + :type key_press: bool + """ + # Disable pylints complaining for this part, #PerformanceOverNeatness + # pylint: disable=too-many-branches,too-many-statements + self._access_lock.acquire() + + if not self._event_files_locked: + self.grab_event_files(True) + + now = datetime.datetime.now() + + # Remove expired keys from store + try: + # Get date and if its less than now its expired + while self._temp_key_store[0][0] < now: + self._temp_key_store.pop(0) + except IndexError: + pass + + # Clean up any threads + if self._clean_counter > 20 and len(self._threads) > 0: + self._clean_counter = 0 + self.clean_macro_threads() + + try: + # Convert event ID to key name + + key_name = self.GAMEPAD_EVENT_MAPPING[key_id] + # Key press + + if self._temp_key_store_active: + colour = random_colour_picker(self._last_colour_choice, COLOUR_CHOICES) + self._last_colour_choice = colour + self._temp_key_store.append((now + self._temp_expire_time, self.GAMEPAD_KEY_MAPPING[key_name], colour)) + + # if self._testing: + # if key_press: + # self._logger.debug("Got Key: {0} Down".format(key_name)) + # else: + # self._logger.debug("Got Key: {0} Up".format(key_name)) + + # Logic for mode switch modifier + if self._mode_modifier: + if key_name == 'MODE_SWITCH' and key_press: + # Start the macro string + self._mode_modifier_key_down = True + self._mode_modifier_combo.clear() + self._mode_modifier_combo.append('MODE') + + elif key_name == 'MODE_SWITCH' and not key_press: + # Release mode_switch + self._mode_modifier_key_down = False + + elif key_press and self._mode_modifier_key_down: + # Any keys pressed whilst mode_switch is down + self._mode_modifier_combo.append(key_name) + + # Override keyname so it now equals a macro + key_name = '+'.join(self._mode_modifier_combo) + + self._logger.debug("Macro String: {0}".format(key_name)) + + if key_name in self._macros and key_press: + self.play_macro(key_name) + + except KeyError as err: + self._logger.exception("Got key error. Couldn't convert event to key name", exc_info=err) + + self._access_lock.release() + + @property + def mode_modifier(self): + """ + Get if the MODE_SWTICH key is to act as a modifier + + :return: True if a modifier, false if not + :rtype: bool + """ + return self._mode_modifier + + @mode_modifier.setter + def mode_modifier(self, value): + """ + Set MODE_SWITCH modifier state + + :param value: Modifier state + :type value: bool + """ + self._mode_modifier = True if value else False + + +class OrbweaverKeyManager(GamepadKeyManager): + GAMEPAD_EVENT_MAPPING = ORBWEAVER_EVENT_MAPPING + GAMEPAD_KEY_MAPPING = ORBWEAVER_KEY_MAPPING diff --git a/openrazer/daemon/openrazer_daemon/misc/macro.py b/openrazer/daemon/openrazer_daemon/misc/macro.py new file mode 100644 index 00000000..eca2ff31 --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/macro.py @@ -0,0 +1,235 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Macro stuff + +Has objects representing key events +Launching programs etc... +""" +import logging +import subprocess +import threading + +# pylint: disable=import-error +from openrazer_daemon.keyboard import XTE_MAPPING + +# This determines if the macro keys are executed with their natural spacing +XTE_SLEEP = False + + +class MacroObject(object): + """ + Macro base object + """ + + def to_dict(self): + """ + Convert the object to a dict to be sent over DBus + + :return: Dictionary + :rtype: dict + """ + raise NotImplementedError() + + @classmethod + def from_dict(cls, values_dict): + """ + Create class from dict + + :param values_dict: Dictionary of values (and a type key) + :type values_dict: dict + + :return: Class object + """ + del values_dict['type'] + return cls(**values_dict) + + +class MacroKey(MacroObject): + """ + Is an object of a key event used in macros + """ + + def __init__(self, key_id, pre_pause, state): + self.key_id = key_id + self.pre_pause = pre_pause + self.state = state + + def __repr__(self): + return '{0} {1}'.format(self.key_id, self.state) + + def __str__(self): + return 'MacroKey|{0}|{1}|{2}'.format(self.key_id, self.pre_pause, self.state) + + def to_dict(self): + return { + 'type': 'MacroKey', + 'key_id': self.key_id, + 'pre_pause': self.pre_pause, + 'state': self.state + } + + @property + def xte_key(self): + """ + Convert key to XTE compatible name + + :return: XTE Name + :rtype: str + """ + return XTE_MAPPING.get(self.key_id, self.key_id) + +# If it only opens a new tab in chroma - https://askubuntu.com/questions/540939/xdg-open-only-opens-a-new-tab-in-a-new-chromium-window-despite-passing-it-a-url + + +class MacroURL(MacroObject): + """ + Is an object of a key event used in macros + """ + + def __init__(self, url): + self.url = url + + def __repr__(self): + return '{0}'.format(self.url) + + def __str__(self): + return 'MacroURL|{0}'.format(self.url) + + def to_dict(self): + return { + 'type': 'MacroURL', + 'url': self.url, + } + + def execute(self): + """ + Open URL in the browser + """ + proc = subprocess.Popen(['xdg-open', self.url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + proc.communicate() + + +class MacroScript(MacroObject): + """ + Is an object of a key event used in macros + """ + + def __init__(self, script, args=None): + self.script = script + if isinstance(args, str): + self.args = ' ' + args + else: + self.args = '' + + def __repr__(self): + return '{0}'.format(self.script) + + def __str__(self): + return 'MacroScript|{0}'.format(self.script) + + def to_dict(self): + return { + 'type': 'MacroScript', + 'script': self.script, + 'args': self.args + } + + def execute(self): + """ + Run script + """ + proc = subprocess.Popen(self.script + self.args, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + proc.communicate() + + +class MacroRunner(threading.Thread): + """ + Thread to run macros + """ + + def __init__(self, device_id, macro_bind, macro_data): + super().__init__() + + self._logger = logging.getLogger('razer.device{0}.macro{1}'.format(device_id, macro_bind)) + self._macro_data = macro_data + self._macro_bind = macro_bind + + @staticmethod + def xte_line(key_event): + """ + Generate a line to be fet into XTE + + :param key_event: Key event object + :type key_event: MacroKey + + :return: String XTE script + :rtype: str + """ + # Save key here to prevent 5odd dictionary lookups + key = key_event.xte_key + + cmd = '' + + if key is not None: + if XTE_SLEEP: + cmd += 'usleep {0}\n'.format(key_event.pre_pause) + + if key_event.state == 'UP': + cmd += 'keyup {0}\n'.format(key) + else: + cmd += 'keydown {0}\n'.format(key) + + return cmd + + def run(self): + """ + Main thread function + """ + + # TODO move the xte-munging to the init + xte = '' + + for event in self._macro_data: + if isinstance(event, MacroKey): + xte += self.xte_line(event) + else: + if xte != '': + proc = subprocess.Popen(['xte'], stdin=subprocess.PIPE) + proc.communicate(input=xte.encode('ascii')) + xte = '' + + # Now run everything else (this just allows for less calls to xte + if not isinstance(event, MacroKey): + event.execute() + + if xte != '': + proc = subprocess.Popen(['xte'], stdin=subprocess.PIPE) + proc.communicate(input=xte.encode('ascii')) + + self._logger.debug("Finished running macro %s", self._macro_bind) + + +def macro_dict_to_obj(macro_dict): + """ + Converts a macro string to its relevant object + + :param macro_dict: Macro string + :type macro_dict: dict + + :return: Macro Object + :rtype: object + + :raises ValueError: When a type isn't known + """ + + if macro_dict['type'] == 'MacroKey': + result = MacroKey.from_dict(macro_dict) + elif macro_dict['type'] == 'MacroURL': + result = MacroURL.from_dict(macro_dict) + elif macro_dict['type'] == 'MacroScript': + result = MacroScript.from_dict(macro_dict) + else: + raise ValueError("unknown type") + + return result diff --git a/openrazer/daemon/openrazer_daemon/misc/ripple_effect.py b/openrazer/daemon/openrazer_daemon/misc/ripple_effect.py new file mode 100644 index 00000000..a77dff8f --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/ripple_effect.py @@ -0,0 +1,256 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Contains the functions and classes to perform ripple effects +""" +import datetime +import logging +import math +import threading +import time + +# pylint: disable=import-error +from openrazer_daemon.keyboard import KeyboardColour + + +class RippleEffectThread(threading.Thread): + """ + Ripple thread. + + This thread contains the run loop which performs all the circle calculations and generating of the binary payload + """ + + def __init__(self, parent, device_number): + super().__init__() + + self._logger = logging.getLogger('razer.device{0}.ripplethread'.format(device_number)) + self._parent = parent + + self._colour = (0, 255, 0) + self._refresh_rate = 0.040 + + self._shutdown = False + self._active = False + + self._rows, self._cols = self._parent._parent.MATRIX_DIMS + + self._keyboard_grid = KeyboardColour(self._rows, self._cols) + + @property + def shutdown(self): + """ + Get the shutdown flag + """ + return self._shutdown + + @shutdown.setter + def shutdown(self, value): + """ + Set the shutdown flag + + :param value: Shutdown + :type value: bool + """ + self._shutdown = value + + @property + def active(self): + """ + Get if the thread is active + + :return: Active + :rtype: bool + """ + return self._active + + @property + def key_list(self): + """ + Get key list + + :return: Key list + :rtype: list + """ + return self._parent.key_list + + def enable(self, colour, refresh_rate): + """ + Enable the ripple effect + + If the colour tuple contains None then it will set the ripple to random colours + :param colour: Colour tuple like (0, 255, 255) + :type colour: tuple + + :param refresh_rate: Refresh rate in seconds + :type refresh_rate: float + """ + if colour[0] is None: + self._colour = None + else: + self._colour = colour + self._refresh_rate = refresh_rate + self._active = True + + def disable(self): + """ + Disable the ripple effect + """ + self._active = False + + def run(self): + """ + Event loop + """ + # pylint: disable=too-many-nested-blocks,too-many-branches + expire_diff = datetime.timedelta(seconds=2) + + # self._parent: RippleManager + # self._parent._parent: The device class (e.g. RazerBlackWidowUltimate2013) + if self._rows == 6 and self._cols == 22: + needslogohandling = True + # a virtual 7th row for logo handling + self._rows += 1 + else: + needslogohandling = False + + # TODO time execution and then sleep for _refresh_rate - time_taken + while not self._shutdown: + if self._active: + # Clear keyboard + self._keyboard_grid.reset_rows() + + now = datetime.datetime.now() + + radiuses = [] + + for expire_time, (key_row, key_col), colour in self.key_list: + event_time = expire_time - expire_diff + + now_diff = now - event_time + + # Current radius is based off a time metric + if self._colour is not None: + colour = self._colour + radiuses.append((key_row, key_col, now_diff.total_seconds() * 24, colour)) + + # Iterate through the rows + for row in range(0, self._rows): + # Iterate through the columns + for col in range(0, self._cols): + # The logo location is physically at (6, 11), logically at (0, 20) + # Skip when we come across the logo location, as the ripple would look wrong + if needslogohandling and row == 0 and col == 20: + continue + + if needslogohandling and row == 6: + if col != 11: + continue + + # To account for logo placement + for cirlce_centre_row, circle_centre_col, rad, colour in radiuses: + radius = math.sqrt(math.pow(cirlce_centre_row - row, 2) + math.pow(circle_centre_col - col, 2)) + if rad >= radius >= rad - 2: + # Again, (0, 20) is the logical location of the logo led + self._keyboard_grid.set_key_colour(0, 20, colour) + break + else: + for cirlce_centre_row, circle_centre_col, rad, colour in radiuses: + radius = math.sqrt(math.pow(cirlce_centre_row - row, 2) + math.pow(circle_centre_col - col, 2)) + if rad >= radius >= rad - 2: + self._keyboard_grid.set_key_colour(row, col, colour) + break + + # Set the colors on the device + payload = self._keyboard_grid.get_total_binary() + + self._parent.set_rgb_matrix(payload) + self._parent.refresh_keyboard() + + # Sleep until the next ripple refresh + time.sleep(self._refresh_rate) + + +class RippleManager(object): + """ + Class which manages the overall process of performing a ripple effect + """ + + def __init__(self, parent, device_number): + self._logger = logging.getLogger('razer.device{0}.ripplemanager'.format(device_number)) + self._parent = parent + self._parent.register_observer(self) + + self._is_closed = False + + self._ripple_thread = RippleEffectThread(self, device_number) + self._ripple_thread.start() + + @property + def key_list(self): + """ + Get the list of keys from the key manager + + :return: List of tuples (expire_time, (key_row, key_col), random_colour) + :rtype: list of tuple + """ + result = [] + if hasattr(self._parent, 'key_manager'): + result = self._parent.key_manager.temp_key_store + + return result + + def set_rgb_matrix(self, payload): + """ + Set the LED matrix on the keyboard + + :param payload: Binary payload + :type payload: bytes + """ + self._parent._set_key_row(payload) + + def refresh_keyboard(self): + """ + Refresh the keyboard + """ + self._parent._set_custom_effect() + + def notify(self, msg): + """ + Receive notificatons from the device (we only care about effects) + + :param msg: Notification + :type msg: tuple + """ + if not isinstance(msg, tuple): + self._logger.warning("Got msg that was not a tuple") + elif msg[0] == 'effect': + # We have a message directed at us + # MSG format + # 0 1 2 3 + # ('effect', Device, 'effectName', 'effectparams'...) + # Device is the device the msg originated from (could be parent device) + if msg[2] == 'setRipple': + # Get (red, green, blue) tuple (args 3:6), and refreshrate arg 6 + self._parent.key_manager.temp_key_store_state = True + self._ripple_thread.enable(msg[3:6], msg[6]) + else: + # Effect other than ripple so stop + self._ripple_thread.disable() + + self._parent.key_manager.temp_key_store_state = False + + def close(self): + """ + Close the manager, stop ripple thread + """ + if not self._is_closed: + self._logger.debug("Closing Ripple Manager") + self._is_closed = True + + self._ripple_thread.shutdown = True + self._ripple_thread.join(timeout=2) + if self._ripple_thread.is_alive(): + self._logger.error("Could not stop RippleEffect thread") + + def __del__(self): + self.close() diff --git a/openrazer/daemon/openrazer_daemon/misc/screensaver_monitor.py b/openrazer/daemon/openrazer_daemon/misc/screensaver_monitor.py new file mode 100644 index 00000000..d40adc5f --- /dev/null +++ b/openrazer/daemon/openrazer_daemon/misc/screensaver_monitor.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Screensaver class which watches dbus signals to see if screensaver is active +""" +import logging +import dbus +import dbus.exceptions + +DBUS_SCREENSAVER_INTERFACES = ( + 'org.cinnamon.ScreenSaver', + 'org.freedesktop.ScreenSaver', + 'org.gnome.ScreenSaver', + 'org.mate.ScreenSaver', + 'org.xfce.ScreenSaver', +) + + +class ScreensaverMonitor(object): + """ + Simple class for monitoring signals on the Session Bus + """ + + def __init__(self, parent): + self._logger = logging.getLogger('razer.screensaver') + self._logger.info("Initialising DBus Screensaver Monitor") + + self._parent = parent + self._monitoring = True + self._active = None + + self._dbus_instances = [] + # Get session bus + bus = dbus.SessionBus() + # Loop through and monitor the signals + for screensaver_interface in DBUS_SCREENSAVER_INTERFACES: + bus.add_signal_receiver(self.signal_callback, dbus_interface=screensaver_interface, signal_name='ActiveChanged') + + @property + def monitoring(self): + """ + Monitoring property, if true then suspend/resume will be actioned. + + :return: If monitoring + :rtype: bool + """ + return self._monitoring + + @monitoring.setter + def monitoring(self, value): + """ + Monitoring property setter, if true then suspend/resume will be actioned. + + :param value: If monitoring + :type: bool + """ + self._monitoring = bool(value) + + def suspend(self): + """ + Suspend the device + """ + self._logger.debug("Received screensaver active signal") + self._parent.suspend_devices() + + def resume(self): + """ + Resume the device + """ + self._logger.debug("Received screensaver inactive signal") + self._parent.resume_devices() + + def signal_callback(self, active): + """ + Called by DBus when a signal is found + + :param active: If the screensaver is active + :type active: dbus.Boolean + """ + active = bool(active) + + if self.monitoring: + if active: + # Only trigger once per state change + if self._active is None or not self._active: + self._active = active + self.suspend() + else: + if self._active is None or self._active: + self._active = active + self.resume() diff --git a/openrazer/daemon/resources/man/openrazer-daemon.8 b/openrazer/daemon/resources/man/openrazer-daemon.8 new file mode 100644 index 00000000..08a35722 --- /dev/null +++ b/openrazer/daemon/resources/man/openrazer-daemon.8 @@ -0,0 +1,84 @@ +.\" Generated by scdoc 1.11.3 +.\" Complete documentation for this program is not available as a GNU info page +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.nh +.ad l +.\" Begin generated content: +.TH "openrazer-daemon" "8" "2024-07-02" +.PP +.SH NAME +.PP +openrazer-daemon - Daemon to manage Razer devices in userspace +.PP +.SH SYNOPSIS +.PP +\fBopenrazer-daemon\fR [options.\&.\&.\&] +.PP +.SH DESCRIPTION +.PP +\fBopenrazer-daemon\fR is a userspace service which is designed to be an intermediary between userspace programs and the Razer drivers.\& It will provide some higher level functions to allow similar operation to the Windows Razer Synapse program.\& This service is designed to be started by xdg-autostart as a session service.\& +.PP +The service has the functionality to sync effects between multiple devices, perform on-the-fly macro recording and playback and reimplements the FN+Keys logic so they work when \fBmacro_keys\fR are enabled.\& The service can also perform various ripple effects and turn off the devices when the screensaver is active.\& +.PP +Note, that all paths shown as defaults, eg ~/.\&local/share/ or ~/.\&config/ can be changed with XDG Base Directory specification variables: \fB$XDG_CONFIG_HOME\fR, \fB$XDG_DATA_HOME\fR and \fB$XDG_RUNTIME_DIR\fR.\& +.PP +.SH OPTIONS +.PP +\fB-v\fR, \fB--verbose\fR +.RS 4 +Enable logging of DEBUG messages.\& +.PP +.RE +\fB-F\fR, \fB--foreground\fR +.RS 4 +Run the daemon in the foreground and don'\&t fork.\& This also enables sending the log output to stdout (in addition to the log file).\& +.PP +.RE +\fB-r\fR, \fB--respawn\fR +.RS 4 +Stop any running daemon first (if one is running) before starting.\& +.PP +.RE +\fB-s\fR, \fB--stop\fR +.RS 4 +Gracefully stop the running daemon.\& +.PP +.RE +\fB--as-root\fR +.RS 4 +Allow the daemon to be started as root.\& +.PP +.RE +\fB--config\fR=\fIconfig_file\fR +.RS 4 +Specifies the location of the config file.\& If this is not provided it will default to ~/.\&config/openrazer/razer.\&conf and create it if needed from the example config.\& +.PP +.RE +\fB--persistence\fR=\fIpersistence_file\fR +.RS 4 +Specifies the location of the persistence file.\& This will be created if non-existent.\& This file will store device states so they persist between reboots.\& +.PP +.RE +\fB--run-dir\fR=\fIrun_directory\fR +.RS 4 +Tells the daemon what directory is its run directory, the directory it will change to once started.\& It will default to \fB$XDG_RUNTIME_DIR\fR, if not set it falls back to ~/.\&local/share/openrazer/.\& +.PP +.RE +\fB--log-dir\fR=\fIlog_directory\fR +.RS 4 +This argument decides where the log directory will be, the daemon itself will handle log rotation as it'\&s a user session service.\& The daemon will default to ~/.\&local/share/openrazer/logs/ for its log directory.\& +.PP +.RE +\fB--test-dir\fR=\fItest_dir\fR +.RS 4 +If provided the daemon will operate in test-driver mode in which it exposes devices that aren'\&t physically connected.\& Use \fIscripts/create_fake_device.\&py\fR or \fIscripts/setup_fake_devices.\&sh\fR from the source repository to create the directory structure.\& +.PP +.RE +.SH DOCUMENTATION +.PP +The full and most up-to-date documentation can be found on our GitHub repository at https://github.\&com/openrazer/openrazer.\& +.PP +.SH SEE ALSO +.PP +\fBrazer.\&conf\fR(5) diff --git a/openrazer/daemon/resources/man/openrazer-daemon.8.scd b/openrazer/daemon/resources/man/openrazer-daemon.8.scd new file mode 100644 index 00000000..82b5c8e1 --- /dev/null +++ b/openrazer/daemon/resources/man/openrazer-daemon.8.scd @@ -0,0 +1,57 @@ +openrazer-daemon(8) + +# NAME + +openrazer-daemon - Daemon to manage Razer devices in userspace + +# SYNOPSIS + +*openrazer-daemon* [options...] + +# DESCRIPTION + +*openrazer-daemon* is a userspace service which is designed to be an intermediary between userspace programs and the Razer drivers. It will provide some higher level functions to allow similar operation to the Windows Razer Synapse program. This service is designed to be started by xdg-autostart as a session service. + +The service has the functionality to sync effects between multiple devices, perform on-the-fly macro recording and playback and reimplements the FN+Keys logic so they work when *macro_keys* are enabled. The service can also perform various ripple effects and turn off the devices when the screensaver is active. + +Note, that all paths shown as defaults, eg ~/.local/share/ or ~/.config/ can be changed with XDG Base Directory specification variables: *$XDG_CONFIG_HOME*, *$XDG_DATA_HOME* and *$XDG_RUNTIME_DIR*. + +# OPTIONS + +*-v*, *--verbose* + Enable logging of DEBUG messages. + +*-F*, *--foreground* + Run the daemon in the foreground and don't fork. This also enables sending the log output to stdout (in addition to the log file). + +*-r*, *--respawn* + Stop any running daemon first (if one is running) before starting. + +*-s*, *--stop* + Gracefully stop the running daemon. + +*--as-root* + Allow the daemon to be started as root. + +*--config*=_config\_file_ + Specifies the location of the config file. If this is not provided it will default to ~/.config/openrazer/razer.conf and create it if needed from the example config. + +*--persistence*=_persistence\_file_ + Specifies the location of the persistence file. This will be created if non-existent. This file will store device states so they persist between reboots. + +*--run-dir*=_run\_directory_ + Tells the daemon what directory is its run directory, the directory it will change to once started. It will default to *$XDG_RUNTIME_DIR*, if not set it falls back to ~/.local/share/openrazer/. + +*--log-dir*=_log\_directory_ + This argument decides where the log directory will be, the daemon itself will handle log rotation as it's a user session service. The daemon will default to ~/.local/share/openrazer/logs/ for its log directory. + +*--test-dir*=_test\_dir_ + If provided the daemon will operate in test-driver mode in which it exposes devices that aren't physically connected. Use _scripts/create\_fake\_device.py_ or _scripts/setup\_fake\_devices.sh_ from the source repository to create the directory structure. + +# DOCUMENTATION + +The full and most up-to-date documentation can be found on our GitHub repository at https://github.com/openrazer/openrazer. + +# SEE ALSO + +*razer.conf*(5) diff --git a/openrazer/daemon/resources/man/razer.conf.5 b/openrazer/daemon/resources/man/razer.conf.5 new file mode 100644 index 00000000..1f90599f --- /dev/null +++ b/openrazer/daemon/resources/man/razer.conf.5 @@ -0,0 +1,76 @@ +.\" Generated by scdoc 1.11.3 +.\" Complete documentation for this program is not available as a GNU info page +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.nh +.ad l +.\" Begin generated content: +.TH "razer.conf" "5" "2024-07-02" +.PP +.SH NAME +.PP +razer.\&conf - configuration file for the OpenRazer Daemon +.PP +.SH DESCRIPTION +.PP +The \fI~/.\&config/openrazer/razer.\&conf\fR (\fB$XDG_CONFIG_HOME\fR is respected, if set) file configures some startup and runtime options of the \fBopenrazer-daemon\fR(8).\& \fBopenrazer-daemon\fR(8) is able to use configuration files specified in non-standard locations by providing the \fI--config\fR argument.\& +.PP +The configuration file is formatted like a .\&INI file and is parsed by Python'\&s ConfigParser.\& +.PP +.SH EXAMPLE +.PP +An example file should be installed under \fI/usr/share/openrazer/razer.\&conf.\&example\fR.\& +.PP +.SH SECTIONS +.PP +.SS GENERAL +.PP +The first section in the configuration file is a \fB[General]\fR section.\& This section contains miscellaneous options.\& +.PP +\fBverbose_logging\fR \fIbool\fR +.RS 4 +This flag specifies if the daemon is to output detailed logging information.\& This value acts the same as if \fB-v\fR or \fB--verbose\fR was passed at the command line.\& +.PP +.RE +.SS STARTUP +.PP +The \fB[Startup]\fR section in the configuration file contains values to be used during startup, for example it can decide if syncing effects will be active when started.\& +.PP +\fBsync_effects_enabled\fR \fIbool\fR +.RS 4 +This flag specifies if the effects syncing logic is active when the daemon is started, not having to wait for the user to activate them.\& +.PP +.RE +\fBdevices_off_on_screensaver\fR \fIbool\fR +.RS 4 +This flag specifies if the functionality to turn off razer devices when the screensaver is activated is active when the daemon starts.\& +.PP +.RE +\fBbattery_notifier\fR \fIbool\fR +.RS 4 +This flag specifies that notifications should be shown regularly with the remaining battery level.\& +.PP +.RE +\fBbattery_notifier_freq\fR \fIint\fR +.RS 4 +This flag specifies how often the notification with the remaining battery level should be shown.\& +.PP +.RE +\fBbattery_notifier_percent\fR \fIint\fR +.RS 4 +This flag specifies what battery percentage the device should reach before sending notifications.\& +.PP +.RE +\fBrestore_persistence\fR \fIbool\fR +.RS 4 +This flag specifies whether effects saved in persistence.\&conf should be applied when the daemon starts.\& +.PP +.RE +\fBpersistence_dual_boot_quirk\fR \fIbool\fR +.RS 4 +This flag specifies whether the persisted effect is applied twice to address a quirk with newer devices that were last changed by Razer Synapse on Windows.\& Only applicable with restore_persistence = True.\& +.PP +.RE +.SH SEE ALSO +.PP +\fBopenrazer-daemon\fR(8) diff --git a/openrazer/daemon/resources/man/razer.conf.5.scd b/openrazer/daemon/resources/man/razer.conf.5.scd new file mode 100644 index 00000000..d057a82b --- /dev/null +++ b/openrazer/daemon/resources/man/razer.conf.5.scd @@ -0,0 +1,53 @@ +razer.conf(5) + +# NAME + +razer.conf - configuration file for the OpenRazer Daemon + +# DESCRIPTION + +The _~/.config/openrazer/razer.conf_ (*$XDG_CONFIG_HOME* is respected, if set) file configures some startup and runtime options of the *openrazer-daemon*(8). *openrazer-daemon*(8) is able to use configuration files specified in non-standard locations by providing the _--config_ argument. + +The configuration file is formatted like a .INI file and is parsed by Python's ConfigParser. + +# EXAMPLE + +An example file should be installed under _/usr/share/openrazer/razer.conf.example_. + +# SECTIONS + +## GENERAL + +The first section in the configuration file is a *[General]* section. This section contains miscellaneous options. + +*verbose_logging* _bool_ + This flag specifies if the daemon is to output detailed logging information. This value acts the same as if *-v* or *--verbose* was passed at the command line. + +## STARTUP + +The *[Startup]* section in the configuration file contains values to be used during startup, for example it can decide if syncing effects will be active when started. + +*sync_effects_enabled* _bool_ + This flag specifies if the effects syncing logic is active when the daemon is started, not having to wait for the user to activate them. + +*devices_off_on_screensaver* _bool_ + This flag specifies if the functionality to turn off razer devices when the screensaver is activated is active when the daemon starts. + +*battery_notifier* _bool_ + This flag specifies that notifications should be shown regularly with the remaining battery level. + +*battery_notifier_freq* _int_ + This flag specifies how often the notification with the remaining battery level should be shown. + +*battery_notifier_percent* _int_ + This flag specifies what battery percentage the device should reach before sending notifications. + +*restore_persistence* _bool_ + This flag specifies whether effects saved in persistence.conf should be applied when the daemon starts. + +*persistence_dual_boot_quirk* _bool_ + This flag specifies whether the persisted effect is applied twice to address a quirk with newer devices that were last changed by Razer Synapse on Windows. Only applicable with restore_persistence = True. + +# SEE ALSO + +*openrazer-daemon*(8) diff --git a/openrazer/daemon/resources/openrazer-daemon.systemd.service.in b/openrazer/daemon/resources/openrazer-daemon.systemd.service.in new file mode 100644 index 00000000..c13eb55a --- /dev/null +++ b/openrazer/daemon/resources/openrazer-daemon.systemd.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=Daemon to manage razer devices in userspace +Documentation=man:openrazer-daemon(8) + +[Service] +Type=dbus +BusName=org.razer +ExecStart=##PREFIX##/bin/openrazer-daemon -F + +[Install] +WantedBy=default.target diff --git a/openrazer/daemon/resources/org.razer.service.in b/openrazer/daemon/resources/org.razer.service.in new file mode 100644 index 00000000..a9927a93 --- /dev/null +++ b/openrazer/daemon/resources/org.razer.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.razer +Exec=##PREFIX##/bin/openrazer-daemon +SystemdService=openrazer-daemon.service diff --git a/openrazer/daemon/resources/razer.conf b/openrazer/daemon/resources/razer.conf new file mode 100644 index 00000000..ff583669 --- /dev/null +++ b/openrazer/daemon/resources/razer.conf @@ -0,0 +1,26 @@ +[General] +# Verbose logging (logs debug messages - lotsa spam) +verbose_logging = False + + +[Startup] +# Set the sync effects flag to true so any assignment of effects will work across devices +sync_effects_enabled = True + +# Turn off the devices when the systems screensaver kicks in +devices_off_on_screensaver = True + +# Battery notifier +battery_notifier = True + +# Battery notification frequency [s] (0 to disable) +battery_notifier_freq = 600 + +# Battery notifications appear when device reaches this percentage +battery_notifier_percent = 33 + +# Apply effects saved to disk when daemon starts +restore_persistence = False + +# Enable this if you dual boot with Windows and the effect isn't restored. Requires restore_persistence = True +persistence_dual_boot_quirk = False diff --git a/openrazer/daemon/run_openrazer_daemon.py b/openrazer/daemon/run_openrazer_daemon.py new file mode 100755 index 00000000..1086d2f2 --- /dev/null +++ b/openrazer/daemon/run_openrazer_daemon.py @@ -0,0 +1,199 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +import argparse +import os +import shutil +import signal +import sys +import time +import logging + +from openrazer_daemon.daemon import RazerDaemon, __version__ +from subprocess import check_output +from time import sleep +from daemonize import Daemonize + +# Basically copied from https://github.com/jleclanche/python-xdg/blob/master/xdg/basedir.py +HOME = os.path.expanduser("~") +XDG_DATA_HOME = os.environ.get("XDG_DATA_HOME", os.path.join(HOME, ".local", "share")) +XDG_CONFIG_HOME = os.environ.get("XDG_CONFIG_HOME", os.path.join(HOME, ".config")) + +RAZER_DATA_HOME = os.path.join(XDG_DATA_HOME, "openrazer") +XDG_RUNTIME_DIR = os.environ.get("XDG_RUNTIME_DIR", RAZER_DATA_HOME) +RAZER_CONFIG_HOME = os.path.join(XDG_CONFIG_HOME, "openrazer") +RAZER_RUNTIME_DIR = XDG_RUNTIME_DIR + +EXAMPLE_CONF_FILE = '/usr/share/openrazer/razer.conf.example' + +CONF_FILE = os.path.join(RAZER_CONFIG_HOME, 'razer.conf') +PERSISTENCE_FILE = os.path.join(RAZER_CONFIG_HOME, 'persistence.conf') +LOG_PATH = os.path.join(RAZER_DATA_HOME, 'logs') + +args = None + + +def parse_args(): + parser = argparse.ArgumentParser() + + parser.add_argument('-v', '--verbose', action='store_true', help='Enable verbose logging') + + parser.add_argument('-F', '--foreground', action='store_true', help='Don\'t fork stay in the foreground') + + parser.add_argument('-r', '--respawn', action='store_true', help='Stop any existing daemon first, if one is running.') + parser.add_argument('-s', '--stop', action='store_true', help='Gracefully stop the existing daemon.') + parser.add_argument('--version', action='version', version='%(prog)s {version}'.format(version=__version__)) + + parser.add_argument('--as-root', action='store_true', help='Allow the daemon to be started as root') + + parser.add_argument('--config', type=str, help='Location of the config file', default=CONF_FILE) + parser.add_argument('--persistence', type=str, help='Location to file for storing device persistence data', default=PERSISTENCE_FILE) + parser.add_argument('--run-dir', type=str, help='Location of the run directory', default=RAZER_RUNTIME_DIR) + parser.add_argument('--log-dir', type=str, help='Location of the log directory', default=LOG_PATH) + + parser.add_argument('--test-dir', type=str, help='Directory containing test driver structure') + + return parser.parse_args() + + +def stop_daemon(args): + pidfile = os.path.join(args.run_dir, 'openrazer-daemon.pid') + try: + with open(pidfile) as f: + pid = int(f.readline().strip()) + + # if we have psutil, check that the process name matches the + # pidfile. Otherwise we might terminate a process that's not + # ours. + try: + import psutil + try: + if psutil.Process(pid).name() != "openrazer-daemon": + raise ProcessLookupError() + except psutil.NoSuchProcess: + raise ProcessLookupError() + except ImportError: + print("Module psutil is missing, not checking for process name") + + os.kill(pid, signal.SIGTERM) + pid_exists = True + delay = 3000 + while delay > 0: + delay -= 100 + try: + time.sleep(0.1) + os.kill(pid, 0) + except ProcessLookupError: + print("Process {} stopped".format(pid)) + pid_exists = False + break + + # if we have to kill it, we probably need to remove the + # pidfile too, otherwise we rely on it to clean up properly + if pid_exists: + print("Process {} is hung, sending SIGKILL".format(pid)) + os.kill(pid, signal.SIGKILL) + os.remove(pidfile) + + except FileNotFoundError: + print("No pidfile found, assuming openrazer-daemon is not running") + except ProcessLookupError: + print("pidfile exists but no process is running. Remove {} and continue".format(pidfile)) + + +def install_example_config_file(config_file): + """ + Installs the example config file + """ + if os.path.exists(config_file): + return + + try: + os.makedirs(os.path.dirname(config_file), exist_ok=True) + if os.path.exists(EXAMPLE_CONF_FILE): + shutil.copy(EXAMPLE_CONF_FILE, config_file) + else: + print('Cant find "{0}"'.format(EXAMPLE_CONF_FILE), file=sys.stderr) + except NotADirectoryError as e: + print("Failed to create {}".format(e.filename), file=sys.stderr) + sys.exit(1) + + +def init_persistence_config(persistence_file): + """ + Creates a new file for persistence, if it does not exist. + """ + if os.path.exists(persistence_file): + return + + try: + os.makedirs(os.path.dirname(persistence_file), exist_ok=True) + with open(persistence_file, "w") as f: + f.writelines("") + + except NotADirectoryError as e: + print("Failed to create {}".format(e.filename), file=sys.stderr) + sys.exit(1) + + +def run_daemon(): + global args + daemon = RazerDaemon(verbose=args.verbose, + log_dir=args.log_dir, + console_log=args.foreground, + config_file=args.config, + persistence_file=args.persistence, + test_dir=args.test_dir) + try: + daemon.run() + except KeyboardInterrupt: + daemon.logger.debug("Exited on user request") + except Exception as err: + daemon.logger.exception("Caught exception", exc_info=err) + + +def run(): + global args + + logger = None + args = parse_args() + + if args.stop: + stop_daemon(args) + sys.exit(0) + + if os.getuid() == 0: + if args.as_root: + print("The daemon is being run as root.") + else: + print("The daemon should not be run as root. If you have a good reason to do so, use the --as-root flag.") + sys.exit(1) + + if args.respawn: + stop_daemon(args) + time.sleep(3) + + # daemonize logs exceptions to its logger (which defaults to the syslog) + # and does not make them appear on stdout/stderr. If we're in foreground + # mode, override that logger with our own. + if args.foreground: + logger = logging.getLogger('run-daemon') + if args.verbose: + logger.setLevel(logging.DEBUG) + + install_example_config_file(args.config) + init_persistence_config(args.persistence) + + os.makedirs(args.run_dir, exist_ok=True) + daemon = Daemonize(app="openrazer-daemon", + pid=os.path.join(args.run_dir, "openrazer-daemon.pid"), + action=run_daemon, + foreground=args.foreground, + verbose=args.verbose, + chdir=args.run_dir, + logger=logger) + daemon.start() + + +if __name__ == "__main__": + run() diff --git a/openrazer/daemon/setup.py b/openrazer/daemon/setup.py new file mode 100644 index 00000000..bced8008 --- /dev/null +++ b/openrazer/daemon/setup.py @@ -0,0 +1,17 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +from setuptools import setup, find_packages + +setup( + name="openrazer_daemon", + version="3.10.3", + packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), + install_requires=[ + "daemonize >= 2.4.7", + "dbus-python >= 1.2.0", + "PyGObject >= 3.20.0", + "pyudev >= 0.16.1", + "setproctitle >= 1.1.8", + ], +) diff --git a/openrazer/daemon/tests/test_effect_sync.py b/openrazer/daemon/tests/test_effect_sync.py new file mode 100644 index 00000000..9d9b4bfd --- /dev/null +++ b/openrazer/daemon/tests/test_effect_sync.py @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import unittest +import unittest.mock + +import openrazer_daemon.misc.effect_sync + +# msg type = effect, arg = orig_device, arg = effect_name, arg.. = arg.. +MSG1 = ('effect', None, 'setBrightness', 255) + +# Static effect message from blackwidow chroma +MSG2 = ('effect', None, 'setStatic', 255, 255, 0) +# Static effect message from blackwidow standard +MSG3 = ('effect', None, 'setStatic') +# Breathing effect message from blackwidow chroma +MSG4 = ('effect', None, 'setBreathSingle', 255, 255, 0) +# Pulsate effect message from blackwidow standard +MSG5 = ('effect', None, 'setPulsate') + + +def logger_mock(*args): + return unittest.mock.MagicMock() + + +class DummyHardwareDevice(object): + def __init__(self): + self.observer_list = [] + + self.disable_notify = None + + self.effect_call = None + + def register_observer(self, obs): + if obs not in self.observer_list: + self.observer_list.append(obs) + + def remove_observer(self, obs): + if obs in self.observer_list: + self.observer_list.remove(obs) + + # Effect functions + def setBrightness(self, brightness): + self.effect_call = ('setBrightness', brightness) + + def setStatic(self): + raise Exception("test") + + +class DummyHardwareBlackWidowStandard(DummyHardwareDevice): + def setStatic(self): + self.effect_call = ('setStatic',) + + def setPulsate(self): + self.effect_call = ('setPulsate',) + + +class DummyHardwareBlackWidowChroma(DummyHardwareDevice): + def setStatic(self, red, green, blue): + self.effect_call = ('setStatic', red, green, blue) + + def setBreathSingle(self, red, green, blue): + self.effect_call = ('setBreathSingle', red, green, blue) + + +class EffectSyncTest(unittest.TestCase): + @unittest.mock.patch('openrazer_daemon.misc.effect_sync.logging.getLogger', logger_mock) + def setUp(self): + self.hardware_device = DummyHardwareDevice() + self.effect_sync = openrazer_daemon.misc.effect_sync.EffectSync(self.hardware_device, 1) + + def test_observers(self): + + self.assertIn(self.effect_sync, self.hardware_device.observer_list) + + # Remove observers + self.effect_sync.close() + + self.assertEqual(len(self.hardware_device.observer_list), 0) + + def test_get_num_arguments(self): + + def func_2_args(x, y): return x + y + + num_args = self.effect_sync.get_num_arguments(func_2_args) + + self.assertEqual(num_args, 2) + + def test_notify_invalid_message(self): + self.effect_sync.notify("test") + + self.assertTrue(self.effect_sync._logger.warning.called) + + def test_notify_message_from_other(self): + # Patch run_effect + self.effect_sync.run_effect = unittest.mock.MagicMock() + + self.effect_sync.notify(MSG1) + + self.assertTrue(self.effect_sync.run_effect.called) + + new_msg = self.effect_sync.run_effect.call_args_list[0][0] + # Check function is called run_effect('setBrightness', 255) + self.assertEqual(new_msg[0], MSG1[2]) + self.assertEqual(new_msg[1], MSG1[3]) + + def test_notify_run_effect(self): + self.effect_sync.notify(MSG1) + + self.assertEqual(self.hardware_device.effect_call[0], MSG1[2]) + self.assertEqual(self.hardware_device.effect_call[1], MSG1[3]) + + self.assertIsNotNone(self.hardware_device.disable_notify) + self.assertFalse(self.hardware_device.disable_notify) + + def test_notify_run_effect_edge_case_1(self): + # Set the parent to a blackwidow (non chroma) + self.hardware_device = DummyHardwareBlackWidowStandard() + self.effect_sync._parent = self.hardware_device + self.hardware_device.register_observer(self.effect_sync) + + self.effect_sync.notify(MSG2) + + self.assertEqual(self.hardware_device.effect_call[0], MSG2[2]) + + def test_notify_run_effect_edge_case_2(self): + # Set the parent to a blackwidow chroma + self.hardware_device = DummyHardwareBlackWidowChroma() + self.effect_sync._parent = self.hardware_device + self.hardware_device.register_observer(self.effect_sync) + + self.effect_sync.notify(MSG3) + + self.assertTupleEqual(self.hardware_device.effect_call, ('setStatic', 0, 255, 0)) + + def test_notify_run_effect_edge_case_3(self): + # Set the parent to a blackwidow (non chroma) + self.hardware_device = DummyHardwareBlackWidowStandard() + self.effect_sync._parent = self.hardware_device + self.hardware_device.register_observer(self.effect_sync) + + self.effect_sync.notify(MSG4) + # Send setBreath but converted it to setPulsate + self.assertEqual(self.hardware_device.effect_call[0], 'setPulsate') + + def test_notify_run_effect_edge_case_4(self): + # Set the parent to a blackwidow chroma + self.hardware_device = DummyHardwareBlackWidowChroma() + self.effect_sync._parent = self.hardware_device + self.hardware_device.register_observer(self.effect_sync) + + self.effect_sync.notify(MSG5) + + self.assertTupleEqual(self.hardware_device.effect_call, ('setBreathSingle', 0, 255, 0)) + + def test_notify_run_effect_edge_case_5(self): + # Exception of standard setStatic() should be caught + self.effect_sync.notify(MSG3) + + # Logger should have called .exception + self.assertTrue(self.effect_sync._logger.exception.called) diff --git a/openrazer/daemon/tests/test_high_level_device.py b/openrazer/daemon/tests/test_high_level_device.py new file mode 100644 index 00000000..9dc2a740 --- /dev/null +++ b/openrazer/daemon/tests/test_high_level_device.py @@ -0,0 +1,213 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import unittest + +import openrazer_daemon.device + +DEVICE1_SERIAL = 'XX000000' +DEVICE1_ID = '0000:0000:0000.0000' + +DEVICE2_SERIAL = 'XX000001' +DEVICE2_ID = '0000:0000:0000.0001' + + +class DummyDBusObject(object): + def __init__(self): + self.notify_msg = None + self.parent = None + + def notify(self, msg): + self.notify_msg = msg + + def register_parent(self, parent): + self.parent = parent + + def notify_parent(self, msg): + self.parent.notify_parent(msg) + + +class DummyParentObject(object): + def __init__(self): + self.notify_msg = None + self.notify_device = None + + def notify(self, device_object, msg): + self.notify_device = device_object + self.notify_msg = msg + +# TODO move device_object creation to setUp + + +class DeviceTest(unittest.TestCase): + def setUp(self): + pass + + def tearDown(self): + pass + + def test_device_properties(self): + dbus_object = DummyDBusObject() + device_object = openrazer_daemon.device.Device(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + + self.assertEqual(device_object.device_id, DEVICE1_ID) + self.assertEqual(device_object.serial, DEVICE1_SERIAL) + self.assertEqual(device_object.dbus, dbus_object) + + def test_device_register_parent(self): + dbus_object = DummyDBusObject() + parent_object = DummyParentObject() + + device_object = openrazer_daemon.device.Device(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + device_object.register_parent(parent_object) + + self.assertEqual(device_object._parent, parent_object) + + def test_device_notify_child(self): + msg = ('test', 1) + + dbus_object = DummyDBusObject() + + device_object = openrazer_daemon.device.Device(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + device_object.notify_child(msg) + + self.assertEqual(dbus_object.notify_msg, msg) + + def test_device_notify_parent(self): + msg = ('test', 1) + + dbus_object = DummyDBusObject() + parent_object = DummyParentObject() + + device_object = openrazer_daemon.device.Device(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + device_object.register_parent(parent_object) + + device_object.notify_parent(msg) + + self.assertEqual(parent_object.notify_msg, msg) + self.assertEqual(parent_object.notify_device, device_object) + + +class DeviceCollectionTest(unittest.TestCase): + def setUp(self): + self.device_collection = openrazer_daemon.device.DeviceCollection() + + def test_add(self): + dbus_object = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + + self.assertIn(DEVICE1_ID, self.device_collection._id_map) + self.assertIn(DEVICE1_SERIAL, self.device_collection._serial_map) + + device_obj_from_id = self.device_collection._id_map[DEVICE1_ID] + device_obj_from_serial = self.device_collection._serial_map[DEVICE1_SERIAL] + + self.assertIs(device_obj_from_id, device_obj_from_serial) + + def test_get(self): + dbus_object = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + + device_obj_by_id = self.device_collection[DEVICE1_ID] + device_obj_by_serial = self.device_collection[DEVICE1_SERIAL] + + self.assertIs(device_obj_by_id, device_obj_by_serial) + + def test_invalid_get(self): + try: + device = self.device_collection.get('INVALID') + except IndexError: + pass + + def test_contains(self): + dbus_object = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + + self.assertIn(DEVICE1_ID, self.device_collection) + self.assertIn(DEVICE1_SERIAL, self.device_collection) + + def test_remove(self): + dbus_object = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + self.assertIn(DEVICE1_ID, self.device_collection) + + self.device_collection.remove(DEVICE1_ID) + self.assertNotIn(DEVICE1_ID, self.device_collection) + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + self.assertIn(DEVICE1_ID, self.device_collection) + + self.device_collection.remove(DEVICE1_SERIAL) + self.assertNotIn(DEVICE1_SERIAL, self.device_collection) + + def test_items(self): + dbus_object = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + + device_id, device_obj1 = list(self.device_collection.id_items())[0] + device_serial, device_obj2 = list(self.device_collection.serial_items())[0] + + self.assertEqual(device_id, DEVICE1_ID) + self.assertEqual(device_serial, DEVICE1_SERIAL) + self.assertIs(device_obj1, device_obj2) + + def test_iter(self): + dbus_object = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object) + + devices = [self.device_collection.get(DEVICE1_ID)] + + for device in self.device_collection: + devices.remove(device) + + self.assertEqual(len(devices), 0) + + def test_serials(self): + dbus_object1 = DummyDBusObject() + dbus_object2 = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object1) + self.device_collection.add(DEVICE2_ID, DEVICE2_SERIAL, dbus_object2) + + serials = self.device_collection.serials() + + self.assertIn(DEVICE1_SERIAL, serials) + self.assertIn(DEVICE2_SERIAL, serials) + + def test_devices(self): + dbus_object1 = DummyDBusObject() + dbus_object2 = DummyDBusObject() + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object1) + self.device_collection.add(DEVICE2_ID, DEVICE2_SERIAL, dbus_object2) + + device_list = self.device_collection.devices + available_dbus = [dbus_object1, dbus_object2] + + for device in device_list: + available_dbus.remove(device.dbus) + + # Ensure both dbus objects have been seen + self.assertEqual(len(available_dbus), 0) + + def test_cross_device_notify(self): + dbus_object1 = DummyDBusObject() + dbus_object2 = DummyDBusObject() + msg = ('test', 1) + + self.device_collection.add(DEVICE1_ID, DEVICE1_SERIAL, dbus_object1) + self.device_collection.add(DEVICE2_ID, DEVICE2_SERIAL, dbus_object2) + + self.assertIs(dbus_object1.notify_msg, None) + self.assertIs(dbus_object2.notify_msg, None) + + dbus_object1.notify_parent(msg) + + # Ensure message gets sent to other devices and not itself + self.assertIs(dbus_object1.notify_msg, None) + self.assertIs(dbus_object2.notify_msg, msg) diff --git a/openrazer/debian/changelog b/openrazer/debian/changelog new file mode 100644 index 00000000..56f700ed --- /dev/null +++ b/openrazer/debian/changelog @@ -0,0 +1,576 @@ +openrazer (3.10.3) noble; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.10.3 + + -- Luca Weiss Wed, 07 May 2025 21:00:47 +0200 + +openrazer (3.10.2) noble; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.10.2 + + -- Luca Weiss Sat, 12 Apr 2025 10:50:41 +0200 + +openrazer (3.10.1) noble; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.10.1 + + -- Luca Weiss Sat, 15 Mar 2025 12:06:17 +0100 + +openrazer (3.10.0) noble; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.10.0 + + -- Luca Weiss Thu, 20 Feb 2025 17:18:46 +0000 + +openrazer (3.9.0) noble; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.9.0 + + -- Luca Weiss Sun, 06 Oct 2024 11:40:51 +0200 + +openrazer (3.8.0) jammy; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.8.0 + + -- Luca Weiss Sun, 14 Apr 2024 11:34:24 +0200 + +openrazer (3.7.0) jammy; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.7.0 + + -- Luca Weiss Wed, 01 Nov 2023 20:47:56 +0200 + +openrazer (3.6.1) jammy; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.6.1 + + -- Luca Weiss Sat, 13 May 2023 17:02:29 +0200 + +openrazer (3.6.0) jammy; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.6.0 + + -- Luca Weiss Sun, 30 Apr 2023 14:23:43 +0200 + +openrazer (3.5.1) jammy; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.5.1 + + -- Luca Weiss Sun, 04 Dec 2022 12:48:59 +0100 + +openrazer (3.5.0) jammy; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.5.0 + + -- Luca Weiss Sun, 20 Nov 2022 15:01:08 +0100 + +openrazer (3.4.0) jammy; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.4.0 + + -- Luca Weiss Sun, 31 Jul 2022 18:00:44 +0200 + +openrazer (3.3.0) focal; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.3.0 + + -- Luca Weiss Sat, 09 Apr 2022 15:57:47 +0200 + +openrazer (3.2.0) focal; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.2.0 + + -- Luca Weiss Sun, 12 Dec 2021 15:58:06 +0100 + +openrazer (3.1.0) focal; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.1.0 + + -- Luca Weiss Sun, 15 Aug 2021 11:42:45 +0200 + +openrazer (3.0.1) bionic; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.0.1 + + -- Luca Weiss Sat, 10 Apr 2021 11:20:13 +0200 + +openrazer (3.0.0) bionic; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v3.0.0 + + -- Luca Weiss Sun, 21 Mar 2021 17:26:04 +0100 + +openrazer (2.9.0) bionic; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.9.0 + + -- Luca Weiss Sun, 08 Nov 2020 17:01:11 +0100 + +openrazer (2.8.0) bionic; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.8.0 + + -- Luca Weiss Sat, 02 May 2020 13:20:33 +0200 + +openrazer (2.7.0) bionic; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.7.0 + + -- Luca Weiss Sat, 11 Jan 2020 11:18:19 +0100 + +openrazer (2.6.0) bionic; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.6.0 + + -- Luca Weiss Mon, 29 Jul 2019 16:22:52 +0200 + +openrazer (2.5.0) bionic; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.5.0 + + -- Luca Weiss Thu, 28 Mar 2019 19:06:54 +0100 + +openrazer (2.4.0) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.4.0 + + -- Luca Weiss Sun, 21 Oct 2018 18:21:27 +0200 + +openrazer (2.3.1) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.3.1 + + -- Luca Weiss Wed, 11 Jul 2018 17:09:23 +0200 + +openrazer (2.3.0) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.3.0 + + -- Luca Weiss Sun, 01 Apr 2018 15:49:19 +0200 + +openrazer (2.2.2) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.2.2 + + -- Luca Weiss Tue, 27 Feb 2018 20:45:43 +0100 + +openrazer (2.2.1) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.2.1 + + -- Luca Weiss Fri, 23 Feb 2018 21:51:47 +0100 + +openrazer (2.2.0) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.2.0 + + -- Luca Weiss Tue, 26 Dec 2017 17:29:26 +0100 + +openrazer (2.1.1) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.1.1 + + -- Luca Weiss Sat, 18 Nov 2017 12:35:27 +0100 + +openrazer (2.1-0ubuntu1) xenial; urgency=high + + * Changelog available at https://github.com/openrazer/openrazer/releases/tag/v2.1 + + -- Luca Weiss Tue, 14 Nov 2017 21:15:36 +0100 + +openrazer (2.0.0-0ubuntu1) xenial; urgency=high + + * Renamed to OpenRazer. + + -- Luke Horwell Sat, 2 Sep 2017 12:42:00 +0000 + +razer (1.1.16-0ubuntu1) xenial; urgency=high + * Added Device - Razer Blade Stealth Mid 2017 + * Added Device - Razer Naga Chroma + * Added Device - Razer AbyssusV2 + * Added fake driver config - Razer BlackWidow Chroma TE + * Added fake driver config - Razer BlackWidow Chroma V2 + * Added fake driver config - Razer BlackWidow Original + Alt + * Added fake driver config - Razer BlackWidow Ultimate 2012, 2013, 2016 + * Added fake driver config - Razer BlackWidow X Chroma, TE + * Added fake driver config - Razer BlackWidow X Ultimate + * Added fake driver config - Razer Blade Late 2016 + * Added fake driver config - Razer Blade Pro Late 2016 + * Added fake driver config - Razer Blade QHD + * Added fake driver config - Razer Blade Stealth Late 2016 + * Added fake driver config - Razer Blade Stealth Mid 2017 + * Added fake driver config - Razer DeathAdder Elite + * Added fake driver config - Razer DeathStalker Chroma + * Added fake driver config - Razer DeathStalker Expert + * Added fake driver config - Razer Diamondback Chroma + * Added fake driver config - Razer Firefly + * Added fake driver config - Razer Imperator + * Added fake driver config - Razer Kraken Classic + * Added fake driver config - Razer Mamba 2012 Wired + * Added fake driver config - Razer Mamba 2012 Wireless + * Added fake driver config - Razer Mamba Chroma Wired + * Added fake driver config - Razer Mamba Chroma TE Wired + * Added fake driver config - Razer Naga Chroma + * Added fake driver config - Razer Naga Hex + * Added fake driver config - Razer Naga Hex Red + * Added fake driver config - Razer Nostromo + * Added fake driver config - Razer Ornata + * Added fake driver config - Razer Ornata Chroma + * Added fake driver config - Razer Orochi 2011 + * Added fake driver config - Razer Orochi 2013 + * Added fake driver config - Razer Orochi Chroma + * Added fake driver config - Razer Ouroboros + * Added fake driver config - Razer Tapian + * Added fake driver config - Razer Tartarus Chroma + * Fixed Bug with laptops logo toggle + * Implemented suspend on Taipan + + -- Terry Cain Fri, 1 Sep 2017 11:28:00 +0000 + +razer (1.1.15-0ubuntu1) xenial; urgency=high + * Added Device - Razer Orochi 2013 + * Added Device - Razer Kraken 7.1 Classic + * Added Device - Razer Tartarus + * Added startlight to pylib + * Added DBus endpoint to list supported devices + * Fixed some Razer image resource urls + * Added replaces in control file to purge razer-chroma-drivers + + -- Terry Cain Sat, 30 Jul 2017 16:12:00 +0000 + +razer (1.1.14-0ubuntu1) xenial; urgency=high + * Added Device - Razer DeathStalker Expert + * Added Device - Razer Orbweaver Chroma + * Added Device - Razer Orochi 2011 + * Fixed bug (in daemon code) where serial is blank or 'Default String' + * Fixed bug where battery notifier will crash if started before notification daemon + * Replaced XDG Autostart with SystemD dbus unit, will autostart when org.razer is accessed + * Updated man pages + * Nerf'd make install + * Moved data dir to .local + * Updated pid check to allow for running as 1 daemon per user + * Added battery endpoints to Mamaba2012 + * z3ntu reformatted all the driver files + + -- Terry Cain Sat, 1 Jul 2017 17:33:00 +0000 + +razer (1.1.13-0ubuntu1) xenial; urgency=high + + * Added Device - Razer Naga Hex (Red) + * Fixed bug where udev was matching whole tree not just device + * Fixed bug in 1byte dpi logic for old devices + * Renamed razer-service back to razer-daemon + * Added more example scripts + * Changed default serials on fake driver configs + + -- Terry Cain Sun, 11 Jun 2017 17:24:00 +0000 + +razer (1.1.12-0ubuntu1) xenial; urgency=high + + * Changed README + * Added in missing DPI for DeathAdder Elite + + -- Terry Cain Wed, 3 May 2017 20:04:00 +0000 + +razer (1.1.11-0ubuntu1) xenial; urgency=low + + * Added Device - Overwatch Razer BlackWidow Chroma + * Added Device - Razer Naga 2014 + * Fixed Bug where serial wasn't reported during device add, causing DBus to die a horrible death + * Fixed inconsistencies where some firmware versions has newlines when interacting with the driver directly + * Added some more mutex's in mouse driver + * Swapped around mice and keyboard block in udev as udev was doing the dodgy + * Added Naga 2014 to fake driver, fixed some other issues there + * Fixed poll_rate constant which was overlooked when numbers changed + * Added .backlight.active properties to mice in pylib + + -- Terry Cain Mon, 17 Apr 2017 11:21:00 +0000 + +razer (1.1.10-0ubuntu1) xenial; urgency=low + + * Fixed bug with Razer Blade QHD Lighting + * Added Device - Razer Blade (Late 2016) + * Added Device - Razer Mamba 2012 (Wired) + * Added Device - Razer Mamba 2012 (Wireless) + * Added Device - Razer Taipan + * Added Device - Razer Nostromo + * Now a DBus method to trigger reactive on firefly + * Added a maxDPI() method to DBus and the python library + * Fixed limited with some Blade RGB payloads + * Fixed some crash conditions + * Slowly prepping driver for some windows ifdefs so that it can compile on windows easily + * Added raw_event function to mice that detects buttons when in device mode (doesn't work yet, proper code is in other branch) + * Started adding mutex's to mice + * Added macros globally in pylib + * Added firefly class to pylib + + -- Terry Cain Sat, 15 Apr 2017 21:54:00 +0000 + +razer (1.1.9-0ubuntu1) xenial; urgency=low + + * Added options to daemon for restarting / stopping using the daemon script + * Added more permission checks so solve some more issues. + * Added Device - Razer Core + * Added Device - Razer Naga Hex + * Added Device - Razer BlackWidow Classic (Alternate) + * Added Device - Razer BlackWidow Chroma V2 + * Added in more urls + * Added custom mode to kraken + * Added config option to stop battery notifications + * Fixed bug when receiving multiple of the same screensaver events + * Major changes to man pages + + -- Terry Cain Sat, 04 Mar 2017 14:47:00 +0000 + +razer (1.1.8-0ubuntu1) xenial; urgency=low + + * Removed driver_verbose make target and made the driver target be verbose + * Added Device - Razer Ornata + * Replaced screensaver thread with some logic to monitor DBus signals + * Daemon now assigns the other interfaces of the device to the main device object + * Fixed typo in Ornata Chroma daemon entry + * Added poll rate to Mamba Chroma + * Driver now has capability to block SuperKey, Alt+Tab, Alt+F4 for Game Mode + + -- Terry Cain Sat, 21 Jan 2017 21:56:00 +0000 + +razer (1.1.7-0ubuntu1) xenial; urgency=low + + * Added Device - Razer Orbweaver + * Fixed error in dependency name + * Fixed error from merging + + -- Terry Cain Tue, 17 Jan 2017 19:29:00 +0000 + +razer (1.1.6-0ubuntu1) xenial; urgency=low + + * Fixed bug in Makefile where drivers wernt being copied over + * Added Device - Razer DeathStalker Chroma + * Added Device - Razer BlackWidow X Ultimate + * Added Device - Razer Ouroboros 2012 + * Added Device - Razer DeathAdder Chroma + * Added Device - Razer Diamonback Chroma + * Added device add and device remove signals to the daemon + * Overhaul'd the daemons device add/remove logic so that it actually works now, and works well + * Added dict's to devices so that the python library can get links to Razer Store and device images + * Added Razer BlackWidow 2012 and BlackWidow Classic to daemon + * Fixed matrix limits on firefly and mug + * Commented out evil log line that spams + * Fixed package dependency issue when on KDE + * Fixed case issue in udev rules + * Added config for kraken v1/2 and mug for device emulation + + -- Terry Cain Mon, 16 Jan 2017 21:11:00 +0000 + +razer (1.1.5-0ubuntu1) xenial; urgency=low + + * Big changes to overall build structure to facilitate proper RPM specfile building + * Added Device - Razer Anansi + * Added Device - Razer Naga Hex V2 + * Added Device - Razer DeathAdder Elite + * Added Device - Razer Kraken 7.1 Chroma + * Added Device - Razer Kraken 7.1 V2 + * Added Device - Razer Chroma Mug Holder + * Added setup.py for daemon and pylib + * Added ability to read DPI + * Added Mouse class in pylib + * Removed unused build dependencies + * Fixed bug with man pages in makefile + * Fixed bug if daemon example config didn't exist + * Fixed bug where daemon device numbering was broken by PR #109 + * Fixed bug where daemon mouse notify thread would die if notify2 wasn't installed + * Fixed bug where screensaver thread would spam exceptions and not try the next DBus option as it found an unimplemented option + * Fixed bug where razer_bcd was left in prerm script + * Fixed bug where razer_mount was not executable, breaks arch builds + * Fixed bugs in DeviceManager, unencapsulating dbus types, some docstring fixes + + -- Terry Cain Fri, 30 Dec 2016 22:15:00 +0000 + +razer (1.1.3-0ubuntu1) trusty; urgency=low + + * Added some more razer laptop support + * Udev possibly fixed. cyanogen revamped the udev rules and mount script :) + * cyanogen also make some much welcome changes to the daemon. + * Possibly more stuff, I cba to look. + + -- Terry Cain Tue, 20 Dec 2016 22:20:00 +0000 + +razer (1.1.2-0ubuntu1) trusty; urgency=low + + * Fucking launchpad + + -- Terry Cain Sun, 4 Dec 2016 10:09:00 +0000 + +razer (1.1.1-0ubuntu1) trusty; urgency=low + + * Fixed merge bug + + -- Terry Cain Sun, 4 Dec 2016 09:54:00 +0000 + +razer (1.1.0-0ubuntu1) trusty; urgency=low + + * Added support for Razer DeathAdder Chroma + * Fixed bug in pylib + + -- Terry Cain Fri, 2 Dec 2016 23:02:00 +0000 + +razer (1.0.17-0ubuntu1) trusty; urgency=low + + * Possible Fix for uname -r kernel mismatch when building on launchpad + + -- Terry Cain Mon, 24 Sep 2016 22:52:00 +0000 + +razer (1.0.16-0ubuntu1) trusty; urgency=low + + * Launchpad Hack 3 + + -- Terry Cain Mon, 24 Sep 2016 20:30:00 +0000 + +razer (1.0.15-0ubuntu1) trusty; urgency=low + + * Launchpad Hack 2 + + -- Terry Cain Mon, 24 Sep 2016 20:30:00 +0000 + +razer (1.0.14-0ubuntu2) trusty; urgency=low + + * Launchpad Hack + + -- Terry Cain Mon, 24 Sep 2016 20:30:00 +0000 + +razer (1.0.14-0ubuntu1) trusty; urgency=low + + * Added support for yet another Razer laptop + + -- Terry Cain Mon, 24 Sep 2016 20:30:00 +0000 + +razer (1.0.13-0ubuntu1) trusty; urgency=low + + * Fixed potential GObject import issues in daemon + * Changed daemon process name from razerdaemon -> razer-service + * Added hardware device class debug output for debugging + * Refactored hardware device class autoimporting so that I no longer forget to import things + * Fixed typo in BlackWidow X Chroma USB PID in the daemon as the class wasn't being used. + * General renaming of imports in hardware class files so the imports are not picked up by the autoimporter + * Added BlackWidow X Chroma Tournament Edition + + -- Terry Cain Fri, 30 Sep 2016 23:32:00 +0000 + +razer (1.0.12-0ubuntu1) trusty; urgency=low + + * Fixed typo where BlackWidow Chroma TE DBus doesn't get macro methods + + -- Terry Cain Tue, 27 Sep 2016 21:11:00 +0000 + +razer (1.0.11-0ubuntu1) trusty; urgency=low + + * Minor daemon logic improvements + * Renamed some daemon methods and added in rudimentary caching for the lulz + * Added capability for Mamba devices to change the colour of individual LEDs + * Bug fixes for daemon in test mode + * Fixed mouse driver for Mamba devices as I broke custom mode when I added Mamba TE support + * Fixed typo in udev rules + * Fixed bug in device simulator and added more configs + * Added multi-device simulation support and can change device contexts in the interactive mode + * Removed test code from pylib + * Cleaned up FX in pylib and added support for dealing with logo and scroll wheel LEDs + * Fixed bug in pylib for Blade Stealth users + + -- Terry Cain Wed, 21 Sep 2016 16:56:00 +0000 + +razer (1.0.10-0ubuntu1) trusty; urgency=low + + * Added Razer Orochi (Wired) + + -- Terry Cain Wed, 21 Sep 2016 16:56:00 +0000 + +razer (1.0.9-0ubuntu1) trusty; urgency=low + + * Updated README + * Added version into various components + * Changed driver so that it does macros better + * Added Razer Imperator 2012 + * Added option in pylib to get whether or not device has dedicated macro keys + * Fixed typo in battery notifier + * Changed key event management to use epoll so should use less CPU + + -- Terry Cain Tue, 20 Sep 2016 23:07:00 +0000 + +razer (1.0.8-0ubuntu1) trusty; urgency=low + + * Added BlackWidow Ultimate 2016 support to daemon + * Cleaned up daemon/pylib a bit + * Added in some newlines before EOF + * Made random ripple depend on its own method in pylib + + -- Terry Cain Fri, 09 Sep 2016 23:11:00 +0000 + +razer (1.0.7-0ubuntu2) trusty; urgency=low + + * Fixed typo in pylib + + -- Terry Cain Wed, 07 Sep 2016 22:56:00 +0000 + +razer (1.0.7-0ubuntu1) trusty; urgency=low + + * Added macro functionality for Tartarus + + -- Terry Cain Wed, 07 Sep 2016 22:09:00 +0000 + +razer (1.0.6-0ubuntu1) trusty; urgency=low + + * Made a change to Makefile that might make LaunchTurd happier + * Added Tartarus support in driver and daemon + * Added Mamba Chroma TE and Mamba Choma Wired to driver + + -- Terry Cain Sun, 04 Sep 2016 11:55:00 +0000 + +razer (1.0.5-0ubuntu1) trusty; urgency=low + + * Fixed some blade stealth daemon stuff + * Updated readme + + -- Terry Cain Thu, 01 Sep 2016 20:43:00 +0000 + +razer (1.0.4-0ubuntu1) trusty; urgency=low + + * Fixed typo + + -- Terry Cain Thu, 01 Sep 2016 20:43:00 +0000 + +razer (1.0.3-0ubuntu1) trusty; urgency=low + + * Moved keyboard.py to daemon + * Added blade stealth to daemon + + -- Terry Cain Wed, 31 Aug 2016 20:07:00 +0000 + +razer (1.0.2-0ubuntu1) trusty; urgency=low + + * Fixed daemon bug when using reactive effects + * Fixed daemon bug whilst getting serial + * Set Logo to use CC BY-SA + * Fixed GTK warning in keyboard.py + + -- Terry Cain Sun, 28 Aug 2016 23:11:00 +0000 + +razer (1.0-0ubuntu1) trusty; urgency=low + + * Initial release of the driver, daemon and Python library. + * Support added: + * Keyboards + * Blackwidow Classic + * Ultimate 2012 + * Ultimate 2013 + * Ultimate 2016 + * Chroma (Regular/TE/X) + * Blade Stealth + * Mice + * Mamba Chroma (Wireless only) + * Abyssus + * Peripherals + * Firefly + * Tartarus + * Autostart at login. + + -- Terry Cain Sat, 19 Mar 2016 09:41:19 +0000 diff --git a/openrazer/debian/compat b/openrazer/debian/compat new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/openrazer/debian/compat @@ -0,0 +1 @@ +12 diff --git a/openrazer/debian/control b/openrazer/debian/control new file mode 100644 index 00000000..10302d36 --- /dev/null +++ b/openrazer/debian/control @@ -0,0 +1,117 @@ +Source: openrazer +Maintainer: Luca Weiss +Section: misc +Priority: optional +Build-Depends: debhelper (>= 11), + dh-python, + python3, + python3-setuptools +# "dh-dkms" for Ubuntu 23.04 and later. "dkms" for earlier releases +Build-Depends-Indep: dh-dkms | dkms (<< 3.0.10) +Standards-Version: 4.6.0 +Vcs-Browser: https://github.com/openrazer/openrazer/ +Vcs-Git: https://github.com/openrazer/openrazer.git +Homepage: https://openrazer.github.io/ + +Package: openrazer-meta +Architecture: all +Depends: ${misc:Depends}, + openrazer-driver-dkms (= ${binary:Version}), + openrazer-daemon (= ${binary:Version}), + python3-openrazer (= ${binary:Version}) +Suggests: openrazer-doc (= ${binary:Version}) +Description: OpenRazer peripheral drivers (metapackage) + OpenRazer is a collection of GNU/Linux drivers for the Razer devices. + Supported devices include keyboards, mice, mouse-mats, headsets and + various other devices. + . + This package is a metapackage which depends on the OpenRazer driver and + userspace daemon, plus a Python library and documentation. + +Package: openrazer-driver-dkms +Architecture: all +Section: kernel +Depends: ${misc:Depends}, + dkms, + udev +Conflicts: razer-chroma-driver, + razer-kernel-modules-dkms, + openrazer-kernel-modules-dkms +Provides: razer-chroma-driver, + razer-kernel-modules-dkms, + openrazer-kernel-modules-dkms +Replaces: razer-chroma-driver, + razer-kernel-modules-dkms, + openrazer-kernel-modules-dkms +Description: OpenRazer peripheral drivers (DKMS) + OpenRazer is a collection of GNU/Linux drivers for the Razer devices. + Supported devices include keyboards, mice, mouse-mats, headsets and + various other devices. + . + This package provides the source code for the OpenRazer kernel module to be + build with dkms. Kernel sources or headers are required to compile this + module. + . + Please read the Troubleshooting Guide in + /usr/share/doc/openrazer-driver-dkms/README.Debian. + + +Package: openrazer-daemon +Architecture: all +Depends: ${misc:Depends}, + ${python3:Depends}, + openrazer-driver-dkms (= ${binary:Version}), + python3-dbus, + python3-gi, + python3-pyudev, + python3-setproctitle, + python3-daemonize (>= 2.4.0), + gir1.2-glib-2.0, + libnotify-bin, + xautomation, + dbus-session-bus +Recommends: python3-openrazer (= ${binary:Version}) +Conflicts: razer-daemon +Provides: razer-daemon +Replaces: razer-daemon +Description: OpenRazer peripheral drivers (daemon) + OpenRazer is a collection of GNU/Linux drivers for the Razer devices. + Supported devices include keyboards, mice, mouse-mats, headsets and + various other devices. + . + This package provides a user-space daemon used to interface with the driver. + It contains a systemd user unit and an AppStream file. + +Package: python3-openrazer +Architecture: all +Section: python +Depends: ${misc:Depends}, + ${python3:Depends}, + openrazer-daemon (= ${binary:Version}), + python3-dbus, + python3-gi, + python3-numpy +Conflicts: python3-razer +Provides: python3-razer +Replaces: python3-razer +Description: OpenRazer peripheral drivers (Python 3) + OpenRazer is a collection of GNU/Linux drivers for the Razer devices. + Supported devices include keyboards, mice, mouse-mats, headsets and + various other devices. + . + This package contains a library for interacting with the OpenRazer daemon. + +Package: openrazer-doc +Architecture: all +Section: doc +Depends: ${misc:Depends} +Conflicts: razer-doc +Provides: razer-doc +Replaces: razer-doc +Description: OpenRazer peripheral drivers (documentation) + OpenRazer is a collection of GNU/Linux drivers for the Razer devices. + Supported devices include keyboards, mice, mouse-mats, headsets and + various other devices. + . + This package contains scripts on how to interact with the daemon and + the driver. diff --git a/openrazer/debian/copyright b/openrazer/debian/copyright new file mode 100644 index 00000000..2f51d829 --- /dev/null +++ b/openrazer/debian/copyright @@ -0,0 +1,395 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: OpenRazer +Source: https://github.com/openrazer/openrazer +Files-Excluded: debian + +Files: * +Copyright: 2015-2016 Terri Cain + 2015-2016 Tim Theede + 2015-2016 Gabriele Musco +License: GPL-2+ + +Files: logo/*.svg +Copyright: 2015-2017 Luke Horwell +License: CC-BY-SA-4.0 + +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + +License: CC-BY-SA-4.0 + Creative Commons Attribution-ShareAlike 4.0 International + Public License + . + By exercising the Licensed Rights (defined below), + You accept and agree to be bound by the terms and conditions + of this Creative Commons Attribution-ShareAlike 4.0 International + Public License ("Public License"). + To the extent this Public License may be interpreted as a contract, + You are granted the Licensed Rights + in consideration of Your acceptance of these terms and conditions, + and the Licensor grants You such rights + in consideration of benefits the Licensor receives + from making the Licensed Material available + under these terms and conditions. + . + Section 1 – Definitions. + . + a. Adapted Material means material + subject to Copyright and Similar Rights + that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, + altered, arranged, transformed, + or otherwise modified in a manner requiring permission + under the Copyright and Similar Rights held by the Licensor. + For purposes of this Public License, + where the Licensed Material is a musical work, + performance, or sound recording, + Adapted Material is always produced + where the Licensed Material is synched + in timed relation with a moving image. + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material + in accordance with the terms and conditions of this Public License. + c. BY-SA Compatible License means a license + listed at , + approved by Creative Commons + as essentially the equivalent of this Public License. + d. Copyright and Similar Rights means copyright + and/or similar rights closely related to copyright + including, without limitation, + performance, broadcast, sound recording, + and Sui Generis Database Rights, + without regard to how the rights are labeled or categorized. + For purposes of this Public License, + the rights specified in Section 2(b)(1)-(2) + are not Copyright and Similar Rights. + e. Effective Technological Measures means those measures + that, in the absence of proper authority, may not be circumvented + under laws fulfilling obligations + under Article 11 of the WIPO Copyright Treaty + adopted on December 20, 1996, + and/or similar international agreements. + f. Exceptions and Limitations means fair use, fair dealing, + and/or any other exception or limitation + to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + g. License Elements means the license attributes + listed in the name of a Creative Commons Public License. + The License Elements of this Public License are + Attribution and ShareAlike. + h. Licensed Material means the artistic or literary work, + database, or other material + to which the Licensor applied this Public License. + i. Licensed Rights means the rights granted to You subject + to the terms and conditions of this Public License, + which are limited to all Copyright and Similar Rights + that apply to Your use of the Licensed Material + and that the Licensor has authority to license. + j. Licensor means the individual(s) or entity(ies) + granting rights under this Public License. + k. Share means to provide material to the public + by any means or process + that requires permission under the Licensed Rights, + such as reproduction, public display, public performance, + distribution, dissemination, communication, or importation, + and to make material available to the public + including in ways that members of the public may access + the material + from a place and at a time individually chosen by them. + l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament + and of the Council of 11 March 1996 + on the legal protection of databases, + as amended and/or succeeded, + as well as other essentially equivalent rights + anywhere in the world. + m. You means the individual or entity + exercising the Licensed Rights under this Public License. + Your has a corresponding meaning. + . + Section 2 – Scope. + . + a. License grant. + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You + a worldwide, royalty-free, non-sublicensable, + non-exclusive, irrevocable license + to exercise the Licensed Rights in the Licensed Material to: + A. reproduce and Share the Licensed Material, + in whole or in part; and + B. produce, reproduce, and Share Adapted Material. + 2. Exceptions and Limitations. + For the avoidance of doubt, + where Exceptions and Limitations apply to Your use, + this Public License does not apply, + and You do not need to comply + with its terms and conditions. + 3. Term. + The term of this Public License is specified in Section 6(a). + 4. Media and formats; technical modifications allowed. + The Licensor authorizes You to exercise the Licensed Rights + in all media and formats + whether now known or hereafter created, + and to make technical modifications necessary to do so. + The Licensor waives and/or agrees not to assert + any right or authority + to forbid You from making technical modifications + necessary to exercise the Licensed Rights, + including technical modifications necessary + to circumvent Effective Technological Measures. + For purposes of this Public License, + simply making modifications authorized by this Section 2(a)(4) + never produces Adapted Material. + 5. Downstream recipients. + A. Offer from the Licensor – Licensed Material. + Every recipient of the Licensed Material + automatically receives an offer from the Licensor + to exercise the Licensed Rights + under the terms and conditions of this Public License. + B. Additional offer from the Licensor – Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor + to exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter’s License You apply. + C. No downstream restrictions. + You may not offer or impose + any additional or different terms or conditions on, + or apply any Effective Technological Measures to, + the Licensed Material + if doing so restricts exercise of the Licensed Rights + by any recipient of the Licensed Material. + 6. No endorsement. + Nothing in this Public License constitutes + or may be construed + as permission to assert or imply + that You are, or that Your use of the Licensed Material is, + connected with, or sponsored, endorsed, + or granted official status by, + the Licensor or others designated to receive attribution + as provided in Section 3(a)(1)(A)(i). + . + b. Other rights. + 1. Moral rights, such as the right of integrity, + are not licensed under this Public License, + nor are publicity, privacy, + and/or other similar personality rights; + however, to the extent possible, + the Licensor waives + and/or agrees not to assert + any such rights held by the Licensor + to the limited extent necessary + to allow You to exercise the Licensed Rights, + but not otherwise. + 2. Patent and trademark rights are not licensed + under this Public License. + 3. To the extent possible, + the Licensor waives any right + to collect royalties from You + for the exercise of the Licensed Rights, + whether directly or through a collecting society + under any voluntary or waivable + statutory or compulsory licensing scheme. + In all other cases + the Licensor expressly reserves any right + to collect such royalties. + . + Section 3 – License Conditions. + . + Your exercise of the Licensed Rights + is expressly made subject to the following conditions. + . + a. Attribution. + 1. If You Share the Licensed Material + (including in modified form), + You must: + A. retain the following + if it is supplied by the Licensor with the Licensed Material: + i. identification of the creator(s) of the Licensed Material + and any others designated to receive attribution, + in any reasonable manner requested by the Licensor + (including by pseudonym if designated); + ii. a copyright notice; + iii. a notice that refers to this Public License; + iv. a notice that refers to the disclaimer of warranties; + v. a URI or hyperlink to the Licensed Material + to the extent reasonably practicable; + B. indicate if You modified the Licensed Material + and retain an indication of any previous modifications; and + C. indicate the Licensed Material is licensed + under this Public License, + and include the text of, or the URI or hyperlink to, + this Public License. + 2. You may satisfy the conditions in Section 3(a)(1) + in any reasonable manner + based on the medium, means, and context + in which You Share the Licensed Material. + For example, + it may be reasonable to satisfy the conditions + by providing a URI or hyperlink to a resource + that includes the required information. + 3. If requested by the Licensor, + You must remove any of the information + required by Section 3(a)(1)(A) + to the extent reasonably practicable. + b. ShareAlike. + In addition to the conditions in Section 3(a), + if You Share Adapted Material You produce, + the following conditions also apply. + 1. The Adapter’s License You apply + must be a Creative Commons license + with the same License Elements, + this version or later, + or a BY-SA Compatible License. + 2. You must include + the text of, or the URI or hyperlink to, + the Adapter's License You apply. + You may satisfy this condition + in any reasonable manner + based on the medium, means, and context + in which You Share Adapted Material. + 3. You may not offer or impose + any additional or different terms or conditions on, + or apply any Effective Technological Measures to, + Adapted Material + that restrict exercise of the rights granted + under the Adapter's License You apply. + . + Section 4 – Sui Generis Database Rights. + . + Where the Licensed Rights include Sui Generis Database Rights + that apply to Your use of the Licensed Material: + . + a. for the avoidance of doubt, + Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share + all or a substantial portion of the contents of the database; + b. if You include all or a substantial portion of + the database contents in a database + in which You have Sui Generis Database Rights, + then the database + in which You have Sui Generis Database Rights + (but not its individual contents) + is Adapted Material, + including for purposes of Section 3(b); and + c. You must comply with the conditions in Section 3(a) + if You Share all or a substantial portion + of the contents of the database. + . + For the avoidance of doubt, + this Section 4 supplements and does not replace + Your obligations under this Public License + where the Licensed Rights include other Copyright and Similar Rights. + . + Section 5 – Disclaimer of Warranties and Limitation of Liability. + . + a. Unless otherwise separately undertaken by the Licensor, + to the extent possible, + the Licensor offers the Licensed Material as-is and as-available, + and makes no representations or warranties + of any kind concerning the Licensed Material, + whether express, implied, statutory, or other. + This includes, without limitation, + warranties of title, merchantability, + fitness for a particular purpose, non-infringement, + absence of latent or other defects, accuracy, + or the presence or absence of errors, + whether or not known or discoverable. + Where disclaimers of warranties are not allowed + in full or in part, + this disclaimer may not apply to You. + b. To the extent possible, + in no event will the Licensor be liable to You + on any legal theory + (including, without limitation, negligence) + or otherwise for any direct, special, + indirect, incidental, consequential, punitive, exemplary, + or other losses, costs, expenses, or damages + arising out of this Public License + or use of the Licensed Material, + even if the Licensor has been advised + of the possibility of such losses, costs, + expenses, or damages. + Where a limitation of liability is not allowed + in full or in part, + this limitation may not apply to You. + c. The disclaimer of warranties + and limitation of liability provided above + shall be interpreted in a manner that, + to the extent possible, + most closely approximates an absolute disclaimer + and waiver of all liability. + . + Section 6 – Term and Termination. + . + a. This Public License applies + for the term of the Copyright + and Similar Rights licensed here. + However, if You fail to comply with this Public License, + then Your rights under this Public License terminate + automatically. + b. Where Your right to use the Licensed Material has terminated + under Section 6(a), it reinstates: + 1. automatically as of the date the violation is cured, + provided it is cured within 30 days + of Your discovery of the violation; or + 2. upon express reinstatement by the Licensor. + c. For the avoidance of doubt, + this Section 6(b) does not affect + any right the Licensor may have to seek remedies + for Your violations of this Public License. + d. For the avoidance of doubt, + the Licensor may also offer the Licensed Material + under separate terms or conditions + or stop distributing the Licensed Material at any time; + however, doing so will not terminate this Public License. + e. Sections 1, 5, 6, 7, and 8 survive termination + of this Public License. + . + Section 7 – Other Terms and Conditions. + . + a. The Licensor shall not be bound + by any additional or different terms or conditions + communicated by You unless expressly agreed. + b. Any arrangements, understandings, or agreements + regarding the Licensed Material not stated herein + are separate from and independent of the terms and conditions + of this Public License. + . + Section 8 – Interpretation. + . + a. For the avoidance of doubt, + this Public License does not, and shall not be interpreted to, + reduce, limit, restrict, or impose conditions on + any use of the Licensed Material + that could lawfully be made without permission + under this Public License. + b. To the extent possible, + if any provision of this Public License is deemed unenforceable, + it shall be automatically reformed + to the minimum extent necessary to make it enforceable. + If the provision cannot be reformed, + it shall be severed from this Public License + without affecting the enforceability + of the remaining terms and conditions. + c. No term or condition of this Public License will be waived + and no failure to comply consented to + unless expressly agreed to by the Licensor. + d. Nothing in this Public License constitutes + or may be interpreted as a limitation upon, or waiver of, + any privileges and immunities that apply to the Licensor or You, + including from the legal processes + of any jurisdiction or authority. diff --git a/openrazer/debian/docs b/openrazer/debian/docs new file mode 100644 index 00000000..b43bf86b --- /dev/null +++ b/openrazer/debian/docs @@ -0,0 +1 @@ +README.md diff --git a/openrazer/debian/openrazer-daemon.install b/openrazer/debian/openrazer-daemon.install new file mode 100644 index 00000000..9f1c6e86 --- /dev/null +++ b/openrazer/debian/openrazer-daemon.install @@ -0,0 +1,5 @@ +usr/bin/openrazer-daemon +usr/lib/python3/dist-packages/openrazer_daemon/ +usr/lib/systemd/user/openrazer-daemon.service +usr/share/dbus-1/services/org.razer.service +usr/share/openrazer/ diff --git a/openrazer/debian/openrazer-daemon.manpages b/openrazer/debian/openrazer-daemon.manpages new file mode 100644 index 00000000..ac1ff104 --- /dev/null +++ b/openrazer/debian/openrazer-daemon.manpages @@ -0,0 +1,2 @@ +daemon/resources/man/razer.conf.5 +daemon/resources/man/openrazer-daemon.8 diff --git a/openrazer/debian/openrazer-doc.examples b/openrazer/debian/openrazer-doc.examples new file mode 100644 index 00000000..e39721e2 --- /dev/null +++ b/openrazer/debian/openrazer-doc.examples @@ -0,0 +1 @@ +examples/* diff --git a/openrazer/debian/openrazer-driver-dkms.README.Debian b/openrazer/debian/openrazer-driver-dkms.README.Debian new file mode 100644 index 00000000..344d2da2 --- /dev/null +++ b/openrazer/debian/openrazer-driver-dkms.README.Debian @@ -0,0 +1,38 @@ +OpenRazer for Debian +------------------- + +# Troubleshooting Guide +# Ref: https://github.com/openrazer/openrazer/wiki/Troubleshooting + + +##### Kernel Headers +If you get a similar message when running: +`sudo dkms install openrazer-driver/1.0.0` + +Please install the kernel headers for your running kernel. +After they are installed they have to be available at +`/lib/modules/$(uname -r)/build` otherwise dkms won't find them. + +``` +Error! echo +Your kernel headers for kernel 4.9.0-kali3-amd64 cannot be found at +/lib/modules/4.9.0-kali3-amd64/build or /lib/modules/4.9.0-kali3-amd64/source. +``` + + +##### plugdev +The daemon requires the current user to be in the user group `plugdev`. +You will get an error message while running `openrazer-daemon -Fv` to indicate that. +To fix it, please run `sudo gpasswd -a $USER plugdev`. + + +##### Secure Boot +If you use Ubuntu, it forces driver signing when secure boot is enabled. +That prevents DKMS from working so either disable secure boot (easiest). +Or check the bottom of this issue on how to sign the modules yourself: +https://github.com/openrazer/openrazer/issues/98 . +You will know that you encounter this issue when running `sudo modprobe razerkbd` +and getting the output of `modprobe: ERROR: could not insert 'razerkbd': Required key not available` + + + -- Dylan Aïssi Tue, 11 Sep 2018 00:00:00 +0200 diff --git a/openrazer/debian/openrazer-driver-dkms.install b/openrazer/debian/openrazer-driver-dkms.install new file mode 100644 index 00000000..284275a0 --- /dev/null +++ b/openrazer/debian/openrazer-driver-dkms.install @@ -0,0 +1,4 @@ +lib/udev/razer_mount +lib/udev/rules.d/99-razer.rules +usr/share/metainfo/io.github.openrazer.openrazer.metainfo.xml +usr/src/openrazer-driver-*/ diff --git a/openrazer/debian/openrazer-driver-dkms.postinst b/openrazer/debian/openrazer-driver-dkms.postinst new file mode 100644 index 00000000..44dc2fc7 --- /dev/null +++ b/openrazer/debian/openrazer-driver-dkms.postinst @@ -0,0 +1,6 @@ +#!/bin/sh +set -e + +#DEBHELPER# + +printf "\n\033[1;36mADD YOUR USER TO THE PLUGDEV GROUP: '\033[1;35msudo gpasswd -a \$USER plugdev\033[1;36m'\033[0m\n" diff --git a/openrazer/debian/python3-openrazer.install b/openrazer/debian/python3-openrazer.install new file mode 100644 index 00000000..7098e2eb --- /dev/null +++ b/openrazer/debian/python3-openrazer.install @@ -0,0 +1 @@ +usr/lib/python3/dist-packages/openrazer/ diff --git a/openrazer/debian/rules b/openrazer/debian/rules new file mode 100755 index 00000000..5ee8f178 --- /dev/null +++ b/openrazer/debian/rules @@ -0,0 +1,22 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# This value is default but we need it below +DEB_DESTDIR=$(CURDIR)/debian/tmp + +%: + dh $@ --with python3,dkms + +override_dh_auto_clean: + echo "No need to clean DKMS modules at packages build time." + echo "DKMS modules are built at packages installation time." + +override_dh_auto_build: + echo "No need to build DKMS modules at packages build time." + echo "DKMS modules are built at packages installation time." + +override_dh_auto_install: + $(MAKE) ubuntu_install install-systemd UDEV_PREFIX=/ DESTDIR=$(DEB_DESTDIR) + +override_dh_dkms: + dh_dkms -p openrazer-driver-dkms -- install_files/dkms/dkms.conf diff --git a/openrazer/debian/source/format b/openrazer/debian/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/openrazer/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/openrazer/debian/watch b/openrazer/debian/watch new file mode 100644 index 00000000..b2ce82db --- /dev/null +++ b/openrazer/debian/watch @@ -0,0 +1,4 @@ +version=4 +opts=repacksuffix=+dfsg,dversionmangle=s/\+dfsg//g,repack,compression=xz,\ + filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/openrazer-$1\.tar\.gz/ \ + https://github.com/openrazer/openrazer/tags .*/v?(\d\S+)\.tar\.gz diff --git a/openrazer/driver/Makefile b/openrazer/driver/Makefile new file mode 100644 index 00000000..e57c0e94 --- /dev/null +++ b/openrazer/driver/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-m := razerkbd.o razermouse.o razerkraken.o razeraccessory.o + +razerkbd-y := razerkbd_driver.o razercommon.o razerchromacommon.o +razermouse-y := razermouse_driver.o razercommon.o razerchromacommon.o +razerkraken-y := razerkraken_driver.o razercommon.o +razeraccessory-y := razeraccessory_driver.o razercommon.o razerchromacommon.o diff --git a/openrazer/driver/razeraccessory_driver.c b/openrazer/driver/razeraccessory_driver.c new file mode 100644 index 00000000..6bb21817 --- /dev/null +++ b/openrazer/driver/razeraccessory_driver.c @@ -0,0 +1,2693 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Terri Cain + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "razeraccessory_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/* + * Version Information + */ +#define DRIVER_DESC "Razer Accessory Device Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE(DRIVER_LICENSE); + +/** + * Send report to the device + */ +static int razer_get_report(struct usb_device *usb_dev, struct razer_report *request, struct razer_report *response) +{ + switch (usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + return razer_get_usb_response(usb_dev, 0x00, request, 0x00, response, RAZER_NEW_DEVICE_WAIT_MIN_US, RAZER_NEW_DEVICE_WAIT_MAX_US); + break; + + default: + return razer_get_usb_response(usb_dev, 0x00, request, 0x00, response, RAZER_ACCESSORY_WAIT_MIN_US, RAZER_ACCESSORY_WAIT_MAX_US); + } +} + +/** + * Function to send to device, get response, and actually check the response + */ +static int razer_send_payload(struct razer_accessory_device *device, struct razer_report *request, struct razer_report *response) +{ + int err; + + request->crc = razer_calculate_crc(request); + + mutex_lock(&device->lock); + err = razer_get_report(device->usb_dev, request, response); + mutex_unlock(&device->lock); + if (err) { + print_erroneous_report(response, "razeraccessory", "Invalid Report Length"); + return err; + } + + /* Check the packet number, class and command are the same */ + if (response->remaining_packets != request->remaining_packets || + response->command_class != request->command_class || + response->command_id.id != request->command_id.id) { + print_erroneous_report(response, "razeraccessory", "Response doesn't match request"); + return -EIO; + } + + switch (response->status) { + case RAZER_CMD_BUSY: + // TODO: Check if this should be an error. + // print_erroneous_report(&response, "razeraccessory", "Device is busy"); + break; + case RAZER_CMD_FAILURE: + print_erroneous_report(response, "razeraccessory", "Command failed"); + return -EIO; + case RAZER_CMD_NOT_SUPPORTED: + print_erroneous_report(response, "razeraccessory", "Command not supported"); + return -EIO; + case RAZER_CMD_TIMEOUT: + print_erroneous_report(response, "razeraccessory", "Command timed out"); + return -EIO; + } + + return 0; +} + +/** + * Device mode function + */ +static void razer_set_device_mode(struct razer_accessory_device *device, unsigned char mode, unsigned char param) +{ + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_set_device_mode(mode, param); + request.transaction_id.id = 0x3F; + + razer_send_payload(device, &request, &response); +} + +/** + * Read device file "version" + * + * Returns a string + */ +static ssize_t razer_attr_read_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", DRIVER_VERSION); +} + +/** + * Read device file "device_type" + * + * Returns friendly string of device type + */ +static ssize_t razer_attr_read_device_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + + char *device_type; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_FIREFLY: + device_type = "Razer Firefly\n"; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + device_type = "Razer Firefly V2\n"; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + device_type = "Razer Firefly V2 Pro\n"; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + device_type = "Razer Firefly Hyperflux\n"; + break; + + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + device_type = "Razer Goliathus\n"; + break; + + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + device_type = "Razer Goliathus Extended\n"; + break; + + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + device_type = "Razer Goliathus Chroma 3XL\n"; + break; + + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + device_type = "Razer Strider Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_CORE: + device_type = "Razer Core\n"; + break; + + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + device_type = "Razer Core X Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + device_type = "Razer Laptop Stand Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + device_type = "Razer Chroma Mug Holder\n"; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + device_type = "Razer Chroma HDK\n"; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + device_type = "Razer Base Station Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + device_type = "Razer Base Station V2 Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + device_type = "Razer Nommo Pro\n"; + break; + + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + device_type = "Razer Nommo Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + device_type = "Razer Kraken Kitty Edition\n"; + break; + + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + device_type = "Razer Mouse Bungee V3 Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + device_type = "Razer Charging Pad Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + device_type = "Razer Mouse Dock\n"; + break; + + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + device_type = "Razer Thunderbolt 4 Dock Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_RAPTOR_27: + device_type = "Razer Raptor 27\n"; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + device_type = "Razer Chroma Addressable RGB Controller\n"; + break; + + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + device_type = "Razer Laptop Stand Chroma V2\n"; + break; + + default: + device_type = "Unknown Device\n"; + break; + } + + return sprintf(buf, device_type); +} + +/** + * Write device file "test" + * + * Does nothing + */ +static ssize_t razer_attr_write_test(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +/** + * Read device file "test" + * + * Returns a string + */ +static ssize_t razer_attr_read_test(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "\n"); +} + +/** + * Write device file "mode_spectrum" + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + request = razer_chroma_standard_matrix_effect_spectrum(); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Must be in normal mode for hardware effects + razer_set_device_mode(device, 0x00, 0x00); + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_reactive" + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char speed; + + if (count != 4) { + printk(KERN_WARNING "razeraccessory: Reactive only accepts Speed, RGB (4byte)\n"); + return -EINVAL; + } + + speed = (unsigned char)buf[0]; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + request = razer_chroma_extended_matrix_effect_reactive(VARSTORE, ZERO_LED, speed, (struct razer_rgb *)&buf[1]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + request = razer_chroma_standard_matrix_effect_reactive(speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_reactive_trigger" + * + * It triggers the mouse pad when written to + */ +static ssize_t razer_attr_write_matrix_reactive_trigger(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + struct razer_rgb rgb = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + // TODO: Fix reactive trigger for Goliathus + request = razer_chroma_extended_matrix_effect_reactive(VARSTORE, ZERO_LED, 0, &rgb); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + // TODO: Issue zeroed out razer_chroma_standard_matrix_effect_reactive report + request = razer_chroma_misc_matrix_reactive_trigger(); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_none" + * + * None effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + request = razer_chroma_standard_matrix_effect_none(); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Must be in normal mode for hardware effects + razer_set_device_mode(device, 0x00, 0x00); + request = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_blinking" + * + * Blinking effect mode is activated whenever the file is written to with 3 bytes + */ +static ssize_t razer_attr_write_matrix_effect_blinking(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 3) { + printk(KERN_WARNING "razeraccessory: Blinking mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + request = razer_chroma_standard_set_led_rgb(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + + razer_send_payload(device, &request, &response); + + msleep(5); + + request = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, CLASSIC_EFFECT_BLINKING); + request.transaction_id.id = 0x3F; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_custom" + * + * Sets the device to custom mode whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_custom(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + request = razer_chroma_standard_matrix_effect_custom_frame(NOSTORE); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_static" + * + * Static effect mode is activated whenever the file is written to with 3 bytes + */ +static ssize_t razer_attr_write_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 3) { + printk(KERN_WARNING "razeraccessory: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + request = razer_chroma_standard_matrix_effect_static((struct razer_rgb*) & buf[0]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Must be in normal mode for hardware effects + razer_set_device_mode(device, 0x00, 0x00); + /** + * Mode switcher required after setting static color effect once and before setting a second time. + * Similar to Naga Trinity? + * + * If the color is not set twice with the mode switch in-between, each subsequent + * setting of the static effect actually sets the previous color... + */ + request = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + request.transaction_id.id = 0x1F; + + razer_send_payload(device, &request, &response); + + request = get_razer_report(0x0f, 0x02, 0x06); + request.arguments[0] = 0x00; + request.arguments[1] = 0x00; + request.arguments[2] = 0x08; + request.arguments[3] = 0x00; + request.arguments[4] = 0x00; + request.arguments[5] = 0x00; + request.transaction_id.id = 0x1F; + + razer_send_payload(device, &request, &response); + + request = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_wave" + * + * When 1 is written (as a character, 0x31) the wave effect is displayed moving anti clockwise + * if 2 is written (0x32) then the wave effect goes clockwise + */ +static ssize_t razer_attr_write_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + unsigned char direction = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + request = razer_chroma_standard_matrix_effect_wave(direction); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Must be in normal mode for hardware effects + razer_set_device_mode(device, 0x00, 0x00); + fallthrough; + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + // Direction values are flipped compared to other devices + direction ^= ((1<<0) | (1<<1)); + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_breath" + * + * Breathing effect mode is activated whenever the file is written to with 1, 3, or 6 bytes + */ +static ssize_t razer_attr_write_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + break; + } + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + break; + } + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Must be in normal mode for hardware effects + razer_set_device_mode(device, 0x00, 0x00); + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + break; + } + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_standard_matrix_effect_breathing_single((struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_standard_matrix_effect_breathing_dual((struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_standard_matrix_effect_breathing_random(); + break; + } + request.transaction_id.id = 0x3F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +static ssize_t razer_attr_write_matrix_effect_starlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char speed = 0; + + if (count != 1 && count != 4 && count != 7) { + printk(KERN_WARNING "razeraccessory: Starlight accepts only 1, 4 or 7 bytes input (speed, [RGB], [RGB])\n"); + return -EINVAL; + } + speed = buf[0]; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + switch(count) { + case 4: // Single colour mode + request = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, ZERO_LED, speed, (struct razer_rgb *)&buf[1]); + break; + + case 7: // Dual colour mode + request = razer_chroma_extended_matrix_effect_starlight_dual(VARSTORE, ZERO_LED, speed, (struct razer_rgb *)&buf[1], (struct razer_rgb *)&buf[4]); + break; + + default: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, ZERO_LED, speed); + break; + } + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_custom_frame" + * + * Format + * ROW_ID START_COL STOP_COL RGB... + */ +static ssize_t razer_attr_write_matrix_custom_frame(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + size_t offset = 0; + unsigned char row_id, start_col, stop_col; + size_t row_length; + + while(offset < count) { + if(offset + 3 > count) { + printk(KERN_ALERT "razeraccessory: Wrong Amount of data provided: Should be ROW_ID, START_COL, STOP_COL, N_RGB\n"); + return -EINVAL; + } + + row_id = buf[offset++]; + start_col = buf[offset++]; + stop_col = buf[offset++]; + + // Validate parameters + if(start_col > stop_col) { + printk(KERN_ALERT "razeraccessory: Start column (%u) is greater than end column (%u)\n", start_col, stop_col); + return -EINVAL; + } + + row_length = ((stop_col + 1) - start_col) * 3; + + if(count < offset + row_length) { + printk(KERN_ALERT "razeraccessory: Not enough RGB to fill row (expecting %lu bytes of RGB data, got %lu)\n", row_length, (count - 3)); + return -EINVAL; + } + + // printk(KERN_INFO "razeraccessory: Row ID: %u, Start: %u, Stop: %u, row length: %lu\n", row_id, start_col, stop_col, row_length); + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CORE: + request = razer_chroma_standard_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + request = razer_chroma_misc_one_row_set_custom_frame(start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request = razer_chroma_extended_matrix_set_custom_frame2(row_id, start_col, stop_col, (unsigned char*)&buf[offset], 0); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Must be in driver mode for custom effects + razer_set_device_mode(device, 0x03, 0x00); + request = razer_chroma_extended_matrix_set_custom_frame2(row_id, start_col, stop_col, (unsigned char*)&buf[offset], 0); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + razer_send_argb_msg(device->usb_dev, row_id, (stop_col - start_col) + 1, (unsigned char*)&buf[offset]); + return count; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + // *3 as its 3 bytes per col (RGB) + offset += row_length; + } + + return count; +} + +/** + * Read device file "serial", doesn't have a proper one so one is generated + * + * Returns a string + */ +static ssize_t razer_attr_read_device_serial(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + char serial_string[51]; + + request = razer_chroma_standard_get_serial(); + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + strncpy(&serial_string[0], &device->serial[0], sizeof(serial_string)); + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + strncpy(&serial_string[0], &response.arguments[0], 22); + serial_string[22] = '\0'; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + strncpy(&serial_string[0], &response.arguments[0], 22); + serial_string[22] = '\0'; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + return sprintf(buf, "%s\n", &serial_string[0]); +} + +/** + * Read device file "get_firmware_version" + * + * Returns a string + */ +static ssize_t razer_attr_read_firmware_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_firmware_version(); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request.transaction_id.id = 0x3F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "v%u.%u\n", response.arguments[0], response.arguments[1]); +} + +/** + * Write device file "device_mode" + */ +static ssize_t razer_attr_write_device_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 2) { + printk(KERN_WARNING "razeraccessory: Device mode only takes 2 bytes.\n"); + return -EINVAL; + } + + request = razer_chroma_standard_set_device_mode(buf[0], buf[1]); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +static ssize_t razer_attr_read_is_mug_present(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = get_razer_report(0x02, 0x81, 0x02); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%u\n", response.arguments[1]); +} + +/** + * Read device file "device_mode" + * + * Returns a string + */ +static ssize_t razer_attr_read_device_mode(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_device_mode(); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + buf[0] = response.arguments[0]; + buf[1] = response.arguments[1]; + + return 2; +} + +/** + * Write device file "set_brightness" + * + * Sets the brightness to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_matrix_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + unsigned char brightness = 0; + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count < 1) { + printk(KERN_WARNING "razeraccessory: Brightness takes an ascii number\n"); + return -EINVAL; + } + + brightness = (unsigned char)simple_strtoul(buf, NULL, 10); + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + request = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + request.transaction_id.id = 0x3F; + device->saved_brightness = brightness; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + request = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + request.transaction_id.id = 0x1F; + device->saved_brightness = brightness; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + request = razer_chroma_standard_set_led_brightness(VARSTORE, BACKLIGHT_LED, brightness); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + request = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + /* Set the brightness for all channels to the requested value */ + request = razer_chroma_extended_matrix_brightness(VARSTORE, ARGB_CH_1_LED, brightness); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_extended_matrix_brightness(VARSTORE, ARGB_CH_2_LED, brightness); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_extended_matrix_brightness(VARSTORE, ARGB_CH_3_LED, brightness); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_extended_matrix_brightness(VARSTORE, ARGB_CH_4_LED, brightness); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_extended_matrix_brightness(VARSTORE, ARGB_CH_5_LED, brightness); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_extended_matrix_brightness(VARSTORE, ARGB_CH_6_LED, brightness); + request.transaction_id.id = 0x3F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "set_brightness" + * + * Returns brightness or -1 if the initial brightness is not known + */ +static ssize_t razer_attr_read_matrix_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report response = {0}; + struct razer_report request = {0}; + unsigned char brightness = 0; + size_t sum = 0; + size_t i; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + brightness = device->saved_brightness; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + /* Get the average brightness of all channels */ + for (i = ARGB_CH_1_LED; i <= ARGB_CH_6_LED; i++) { + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, i); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + sum += response.arguments[2]; + } + brightness = sum / 6; + break; + + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + request = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + brightness = response.arguments[2]; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + return sprintf(buf, "%d\n", brightness); +} + +/** + * Write charge brightness device files + * + * Sets the brightness to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_set_charge_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int led) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + unsigned char brightness = 0; + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count < 1) { + printk(KERN_WARNING "razeraccessory: Brightness takes an ascii number\n"); + return -EINVAL; + } + + brightness = (unsigned char)simple_strtoul(buf, NULL, 10); + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + request = razer_chroma_extended_matrix_brightness(VARSTORE, led, brightness); + request.transaction_id.id = 0x1F; + device->saved_brightness = brightness; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read charge brightness device files + * + * Returns brightness or -1 if the initial brightness is not known + */ +static ssize_t razer_attr_read_set_charge_brightness(struct device *dev, struct device_attribute *attr, char *buf, int led) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + unsigned char brightness = 0; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + brightness = device->saved_brightness; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + return sprintf(buf, "%d\n", brightness); +} + +/** + * Read device file "charging_led_brightness" + */ +static ssize_t razer_attr_read_charging_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_set_charge_brightness(dev, attr, buf, CHARGING_LED); +} + +/** + * Write device file "charging_led_brightness" + */ +static ssize_t razer_attr_write_charging_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_set_charge_brightness(dev, attr, buf, count, CHARGING_LED); +} + +/** + * Read device file "fast_charging_led_brightness" + */ +static ssize_t razer_attr_read_fast_charging_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_set_charge_brightness(dev, attr, buf, FAST_CHARGING_LED); +} + +/** + * Write device file "fast_charging_led_brightness" + */ +static ssize_t razer_attr_write_fast_charging_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_set_charge_brightness(dev, attr, buf, count, FAST_CHARGING_LED); +} + +/** + * Read device file "fully_charged_led_brightness" + */ +static ssize_t razer_attr_read_fully_charged_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_set_charge_brightness(dev, attr, buf, FULLY_CHARGED_LED); +} + +/** + * Write device file "fully_charged_led_brightness" + */ +static ssize_t razer_attr_write_fully_charged_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_set_charge_brightness(dev, attr, buf, count, FULLY_CHARGED_LED); +} + +/** + * Write device file "mode_spectrum" + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_charge_mode_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int led) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, led); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "charging_mode_spectrum" + */ +static ssize_t razer_attr_write_charging_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_charge_mode_spectrum(dev, attr, buf, count, CHARGING_LED); +} + +/** + * Write device file "fast_charging_mode_spectrum" + */ +static ssize_t razer_attr_write_fast_charging_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_charge_mode_spectrum(dev, attr, buf, count, FAST_CHARGING_LED); +} + +/** + * Write device file "fully_charged_mode_spectrum" + */ +static ssize_t razer_attr_write_fully_charged_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_charge_mode_spectrum(dev, attr, buf, count, FULLY_CHARGED_LED); +} + +static ssize_t razer_attr_write_matrix_effect_none_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int led) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, led); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "charging_mode_none" + */ +static ssize_t razer_attr_write_charging_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, CHARGING_LED); +} + +/** + * Write device file "fast_charging_mode_none" + */ +static ssize_t razer_attr_write_fast_charging_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, FAST_CHARGING_LED); +} + +/** + * Write device file "fully_charged_mode_none" + */ +static ssize_t razer_attr_write_fully_charged_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, FULLY_CHARGED_LED); +} + +static ssize_t razer_attr_write_matrix_effect_static_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int led) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 3) { + printk(KERN_WARNING "razeraccessory: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + request = razer_chroma_extended_matrix_effect_static(VARSTORE, led, (struct razer_rgb*) & buf[0]); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "charging_mode_static" + */ +static ssize_t razer_attr_write_charging_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, CHARGING_LED); +} + +/** + * Write device file "fast_charging_mode_static" + */ +static ssize_t razer_attr_write_fast_charging_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, FAST_CHARGING_LED); +} + +/** + * Write device file "fully_charged_mode_static" + */ +static ssize_t razer_attr_write_fully_charged_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, FULLY_CHARGED_LED); +} + +static ssize_t razer_attr_write_matrix_effect_wave_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int led) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + unsigned char direction = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Direction values are flipped compared to other devices + direction ^= ((1<<0) | (1<<1)); + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, led, direction); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "charging_mode_wave" + */ +static ssize_t razer_attr_write_charging_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, CHARGING_LED); +} + +/** + * Write device file "fast_charging_mode_wave" + */ +static ssize_t razer_attr_write_fast_charging_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, FAST_CHARGING_LED); +} + +/** + * Write device file "fully_charged_mode_wave" + */ +static ssize_t razer_attr_write_fully_charged_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, FULLY_CHARGED_LED); +} + +static ssize_t razer_attr_write_matrix_effect_breath_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int led) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, led, (struct razer_rgb *)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, led, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, led); + break; + } + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razeraccessory: Unknown device\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "charging_mode_breath" + */ +static ssize_t razer_attr_write_charging_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, CHARGING_LED); +} + +/** + * Write device file "fast_charging_mode_breath" + */ +static ssize_t razer_attr_write_fast_charging_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, FAST_CHARGING_LED); +} + +/** + * Write device file "fully_charged_mode_breath" + */ +static ssize_t razer_attr_write_fully_charged_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, FULLY_CHARGED_LED); +} + +/** + * Sets the brightness to the ASCII number + */ +static ssize_t razer_attr_write_channel_led_brightness(unsigned char led, struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + unsigned char brightness = 0; + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count < 1) { + printk(KERN_WARNING "razeraccessory: Brightness takes an ascii number\n"); + return -EINVAL; + } + + brightness = (unsigned char)simple_strtoul(buf, NULL, 10); + + request = razer_chroma_extended_matrix_brightness(VARSTORE, led, brightness); + request.transaction_id.id = 0x3F; + + razer_send_payload(device, &request, &response); + + return count; +} + +static ssize_t razer_attr_write_channel1_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_led_brightness(ARGB_CH_1_LED, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel2_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_led_brightness(ARGB_CH_2_LED, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel3_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_led_brightness(ARGB_CH_3_LED, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel4_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_led_brightness(ARGB_CH_4_LED, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel5_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_led_brightness(ARGB_CH_5_LED, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel6_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_led_brightness(ARGB_CH_6_LED, dev, attr, buf, count); +} + +/** + * Read device file "channelX_size" + */ +static ssize_t razer_attr_read_channel_size(unsigned int channel, struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = get_razer_report(0x0f, 0x88, 0x0d); + request.transaction_id.id = 0x1F; + request.arguments[0] = 0x06; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[channel * 2]); +} + +static ssize_t razer_attr_read_channel1_size(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_size(1, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel2_size(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_size(2, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel3_size(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_size(3, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel4_size(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_size(4, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel5_size(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_size(5, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel6_size(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_size(6, dev, attr, buf); +} + +/** + * Write device file "channelX_size" + */ +static ssize_t razer_attr_write_channel_size(unsigned int channel, struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned char sz; + struct razer_report request = {0}; + struct razer_report response = {0}; + struct razer_accessory_device *device; + + if (count < 1) { + printk(KERN_WARNING "razeraccessory: Size takes an ascii number\n"); + return -EINVAL; + } + + device = dev_get_drvdata(dev); + + /* Get existing sizes */ + request = get_razer_report(0x0f, 0x88, 0x0d); + request.transaction_id.id = 0x1F; + request.arguments[0] = 0x06; + + razer_send_payload(device, &request, &response); + + /* Set new sizes */ + sz = (unsigned char)simple_strtoul(buf, NULL, 10); + + request = get_razer_report(0x0f, 0x08, 0x0d); + request.transaction_id.id = 0xFF; + request.arguments[0] = 0x06; + request.arguments[1] = 0x01; + request.arguments[2] = channel == 1 ? sz : response.arguments[2]; + request.arguments[3] = 0x02; + request.arguments[4] = channel == 2 ? sz : response.arguments[4]; + request.arguments[5] = 0x03; + request.arguments[6] = channel == 3 ? sz : response.arguments[6]; + request.arguments[7] = 0x04; + request.arguments[8] = channel == 4 ? sz : response.arguments[8]; + request.arguments[9] = 0x05; + request.arguments[10] = channel == 5 ? sz : response.arguments[10]; + request.arguments[11] = 0x06; + request.arguments[12] = channel == 6 ? sz : response.arguments[12]; + + razer_send_payload(device, &request, &response); + + return count; +} + +static ssize_t razer_attr_write_channel1_size(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_size(1, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel2_size(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_size(2, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel3_size(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_size(3, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel4_size(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_size(4, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel5_size(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_size(5, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_channel6_size(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_channel_size(6, dev, attr, buf, count); +} + +static ssize_t razer_attr_write_reset_channels(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + + /* Get existing sizes */ + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned int i; + + for (i = 0; i < 6; i++) { + request = get_razer_report(0x0f, 0x04, 0x03); + request.transaction_id.id = 0x1F; + request.arguments[0] = 0x01; + request.arguments[1] = ARGB_CH_1_LED + i; + request.arguments[2] = 0xff; + + razer_send_payload(device, &request, &response); + } + + request = get_razer_report(0x00, 0xb7, 0x01); + request.transaction_id.id = 0x1F; + request.arguments[0] = 0x00; + razer_send_payload(device, &request, &response); + + request = get_razer_report(0x00, 0x36, 0x01); + request.transaction_id.id = 0x1F; + request.arguments[0] = 0x01; + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "channelX_led_brightness" + * + * Returns brightness or -1 if the initial brightness is not known + */ +static ssize_t razer_attr_read_channel_led_brightness(unsigned char led, struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_accessory_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char brightness = 0; + + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, led); + request.transaction_id.id = 0x3F; + + razer_send_payload(device, &request, &response); + brightness = response.arguments[2]; + + return sprintf(buf, "%d\n", brightness); +} + +static ssize_t razer_attr_read_channel1_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_led_brightness(ARGB_CH_1_LED, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel2_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_led_brightness(ARGB_CH_2_LED, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel3_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_led_brightness(ARGB_CH_3_LED, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel4_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_led_brightness(ARGB_CH_4_LED, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel5_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_led_brightness(ARGB_CH_5_LED, dev, attr, buf); +} + +static ssize_t razer_attr_read_channel6_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_channel_led_brightness(ARGB_CH_6_LED, dev, attr, buf); +} + +/** + * Set up the device driver files + + * + * Read only is 0444 + * Write only is 0220 + * Read and write is 0664 + */ + +static DEVICE_ATTR(test, 0660, razer_attr_read_test, razer_attr_write_test); +static DEVICE_ATTR(version, 0440, razer_attr_read_version, NULL); +static DEVICE_ATTR(device_type, 0440, razer_attr_read_device_type, NULL); +static DEVICE_ATTR(device_mode, 0660, razer_attr_read_device_mode, razer_attr_write_device_mode); +static DEVICE_ATTR(device_serial, 0440, razer_attr_read_device_serial, NULL); +static DEVICE_ATTR(firmware_version, 0440, razer_attr_read_firmware_version, NULL); + +static DEVICE_ATTR(matrix_effect_none, 0220, NULL, razer_attr_write_matrix_effect_none); +static DEVICE_ATTR(matrix_effect_spectrum, 0220, NULL, razer_attr_write_matrix_effect_spectrum); +static DEVICE_ATTR(matrix_effect_static, 0220, NULL, razer_attr_write_matrix_effect_static); +static DEVICE_ATTR(matrix_effect_reactive, 0220, NULL, razer_attr_write_matrix_effect_reactive); +static DEVICE_ATTR(matrix_effect_breath, 0220, NULL, razer_attr_write_matrix_effect_breath); +static DEVICE_ATTR(matrix_effect_custom, 0220, NULL, razer_attr_write_matrix_effect_custom); +static DEVICE_ATTR(matrix_effect_wave, 0220, NULL, razer_attr_write_matrix_effect_wave); +static DEVICE_ATTR(matrix_effect_blinking, 0220, NULL, razer_attr_write_matrix_effect_blinking); +static DEVICE_ATTR(matrix_effect_starlight, 0220, NULL, razer_attr_write_matrix_effect_starlight); +static DEVICE_ATTR(matrix_brightness, 0660, razer_attr_read_matrix_brightness, razer_attr_write_matrix_brightness); +static DEVICE_ATTR(matrix_custom_frame, 0220, NULL, razer_attr_write_matrix_custom_frame); +static DEVICE_ATTR(matrix_reactive_trigger, 0220, NULL, razer_attr_write_matrix_reactive_trigger); + +static DEVICE_ATTR(charging_led_brightness, 0660, razer_attr_read_charging_led_brightness, razer_attr_write_charging_led_brightness); +static DEVICE_ATTR(charging_matrix_effect_wave, 0220, NULL, razer_attr_write_charging_matrix_effect_wave); +static DEVICE_ATTR(charging_matrix_effect_spectrum, 0220, NULL, razer_attr_write_charging_matrix_effect_spectrum); +static DEVICE_ATTR(charging_matrix_effect_breath, 0220, NULL, razer_attr_write_charging_matrix_effect_breath); +static DEVICE_ATTR(charging_matrix_effect_static, 0220, NULL, razer_attr_write_charging_matrix_effect_static); +static DEVICE_ATTR(charging_matrix_effect_none, 0220, NULL, razer_attr_write_charging_matrix_effect_none); + +static DEVICE_ATTR(fast_charging_led_brightness, 0660, razer_attr_read_fast_charging_led_brightness, razer_attr_write_fast_charging_led_brightness); +static DEVICE_ATTR(fast_charging_matrix_effect_wave, 0220, NULL, razer_attr_write_fast_charging_matrix_effect_wave); +static DEVICE_ATTR(fast_charging_matrix_effect_spectrum, 0220, NULL, razer_attr_write_fast_charging_matrix_effect_spectrum); +static DEVICE_ATTR(fast_charging_matrix_effect_breath, 0220, NULL, razer_attr_write_fast_charging_matrix_effect_breath); +static DEVICE_ATTR(fast_charging_matrix_effect_static, 0220, NULL, razer_attr_write_fast_charging_matrix_effect_static); +static DEVICE_ATTR(fast_charging_matrix_effect_none, 0220, NULL, razer_attr_write_fast_charging_matrix_effect_none); + +static DEVICE_ATTR(fully_charged_led_brightness, 0660, razer_attr_read_fully_charged_led_brightness, razer_attr_write_fully_charged_led_brightness); +static DEVICE_ATTR(fully_charged_matrix_effect_wave, 0220, NULL, razer_attr_write_fully_charged_matrix_effect_wave); +static DEVICE_ATTR(fully_charged_matrix_effect_spectrum, 0220, NULL, razer_attr_write_fully_charged_matrix_effect_spectrum); +static DEVICE_ATTR(fully_charged_matrix_effect_breath, 0220, NULL, razer_attr_write_fully_charged_matrix_effect_breath); +static DEVICE_ATTR(fully_charged_matrix_effect_static, 0220, NULL, razer_attr_write_fully_charged_matrix_effect_static); +static DEVICE_ATTR(fully_charged_matrix_effect_none, 0220, NULL, razer_attr_write_fully_charged_matrix_effect_none); + +static DEVICE_ATTR(reset_channels, 0220, NULL, razer_attr_write_reset_channels); +static DEVICE_ATTR(channel1_size, 0660, razer_attr_read_channel1_size, razer_attr_write_channel1_size); +static DEVICE_ATTR(channel2_size, 0660, razer_attr_read_channel2_size, razer_attr_write_channel2_size); +static DEVICE_ATTR(channel3_size, 0660, razer_attr_read_channel3_size, razer_attr_write_channel3_size); +static DEVICE_ATTR(channel4_size, 0660, razer_attr_read_channel4_size, razer_attr_write_channel4_size); +static DEVICE_ATTR(channel5_size, 0660, razer_attr_read_channel5_size, razer_attr_write_channel5_size); +static DEVICE_ATTR(channel6_size, 0660, razer_attr_read_channel6_size, razer_attr_write_channel6_size); +static DEVICE_ATTR(channel1_led_brightness, 0660, razer_attr_read_channel1_led_brightness, razer_attr_write_channel1_led_brightness); +static DEVICE_ATTR(channel2_led_brightness, 0660, razer_attr_read_channel2_led_brightness, razer_attr_write_channel2_led_brightness); +static DEVICE_ATTR(channel3_led_brightness, 0660, razer_attr_read_channel3_led_brightness, razer_attr_write_channel3_led_brightness); +static DEVICE_ATTR(channel4_led_brightness, 0660, razer_attr_read_channel4_led_brightness, razer_attr_write_channel4_led_brightness); +static DEVICE_ATTR(channel5_led_brightness, 0660, razer_attr_read_channel5_led_brightness, razer_attr_write_channel5_led_brightness); +static DEVICE_ATTR(channel6_led_brightness, 0660, razer_attr_read_channel6_led_brightness, razer_attr_write_channel6_led_brightness); + +static DEVICE_ATTR(is_mug_present, 0440, razer_attr_read_is_mug_present, NULL); + +static void razer_accessory_init(struct razer_accessory_device *dev, struct usb_interface *intf, struct hid_device *hdev) +{ + struct usb_device *usb_dev = interface_to_usbdev(intf); + unsigned int rand_serial = 0; + + // Initialise mutex + mutex_init(&dev->lock); + // Setup values + dev->usb_dev = usb_dev; + dev->usb_vid = usb_dev->descriptor.idVendor; + dev->usb_pid = usb_dev->descriptor.idProduct; + dev->usb_interface_protocol = intf->cur_altsetting->desc.bInterfaceProtocol; + + // Get a "random" integer + get_random_bytes(&rand_serial, sizeof(unsigned int)); + sprintf(&dev->serial[0], "MUG%012u", rand_serial); +} + +/** + * Say that we want to allow EV_KEY events and that we want to allow KEY_PROG1 events specifically + */ +static int razer_setup_input(struct input_dev *input, struct hid_device *hdev) +{ + __set_bit(EV_KEY, input->evbit); + __set_bit(KEY_PROG1, input->keybit); + + return 0; +} + +/** + * Setup the input device now that its been added to our struct + */ +static int razer_input_configured(struct hid_device *hdev, struct hid_input *hi) +{ + struct razer_accessory_device *device = hid_get_drvdata(hdev); + int ret; + + ret = razer_setup_input(device->input, hdev); + if (ret) { + hid_err(hdev, "magicmouse setup input failed (%d)\n", ret); + /* clean msc->input to notify probe() of the failure */ + device->input = NULL; + return ret; + } + + return 0; +} + +/** + * Basically map a hid input to our structure + */ +static int razer_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) +{ + struct razer_accessory_device *device = hid_get_drvdata(hdev); + + if (!device->input) + device->input = hi->input; + + return 0; +} + +/** + * Match method checks whether this driver should be used for a given HID device + */ +static bool razer_accessory_match(struct hid_device *hdev, bool ignore_special_driver) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + + switch (usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + if (intf->cur_altsetting->desc.bInterfaceNumber != 0) { + dev_info(&intf->dev, "skipping secondary interface\n"); + return false; + } + } + + return true; +} + +/** + * Probe method is ran whenever a device is binded to the driver + */ +static int razer_accessory_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int retval = 0; + unsigned char expected_protocol = USB_INTERFACE_PROTOCOL_MOUSE; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct razer_accessory_device *dev = NULL; + + dev = kzalloc(sizeof(struct razer_accessory_device), GFP_KERNEL); + if(dev == NULL) { + dev_err(&intf->dev, "out of memory\n"); + return -ENOMEM; + } + + // Init data + razer_accessory_init(dev, intf, hdev); + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + expected_protocol = 0; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + expected_protocol = USB_INTERFACE_PROTOCOL_MOUSE; + break; + + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + expected_protocol = USB_INTERFACE_PROTOCOL_KEYBOARD; + break; + } + + if(dev->usb_interface_protocol == expected_protocol) { + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_version); // Get driver version + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_test); // Test mode + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_type); // Get string of device type + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_mode); // Get string of device mode + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_serial); // Get string of device serial + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_firmware_version); // Get string of device fw version + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Custom effect frame + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); // Brightness + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + // Razer has also added a "Fast Wave" effect for at least this device + // which uses the same effect command but a speed parameter of 0x10. + // It has not been implemented. + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charging_led_brightness); // Charging effects + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charging_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charging_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charging_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charging_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charging_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fast_charging_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fast_charging_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fast_charging_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fast_charging_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fast_charging_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fast_charging_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fully_charged_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fully_charged_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fully_charged_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fully_charged_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fully_charged_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fully_charged_matrix_effect_none); + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + // Device initial brightness is always 100% anyway + dev->saved_brightness = 0xFF; + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_reactive_trigger); // Reactive trigger + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_is_mug_present); // Is cup present + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_blinking); // Blinking effect + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_reset_channels); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel1_size); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel2_size); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel3_size); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel4_size); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel5_size); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel6_size); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel1_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel2_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel3_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel4_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel5_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_channel6_led_brightness); + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + // Needs to be in "Normal" mode for idle effects to function properly + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + break; + + default: + // Needs to be in "Driver" mode just to function + razer_set_device_mode(dev, 0x03, 0x00); + break; + } + } + + hid_set_drvdata(hdev, dev); + dev_set_drvdata(&hdev->dev, dev); + + if(hid_parse(hdev)) { + hid_err(hdev, "parse failed\n"); + goto exit_free; + } + + if (hid_hw_start(hdev, HID_CONNECT_DEFAULT)) { + hid_err(hdev, "hw start failed\n"); + goto exit_free; + } + + usb_disable_autosuspend(usb_dev); + + return 0; + +exit_free: + kfree(dev); + return retval; +} + +/** + * Unbind function + */ +static void razer_accessory_disconnect(struct hid_device *hdev) +{ + unsigned char expected_protocol = USB_INTERFACE_PROTOCOL_MOUSE; + struct razer_accessory_device *dev; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + + dev = hid_get_drvdata(hdev); + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + expected_protocol = 0; + break; + + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + expected_protocol = USB_INTERFACE_PROTOCOL_MOUSE; + break; + + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + expected_protocol = USB_INTERFACE_PROTOCOL_KEYBOARD; + break; + } + + if(dev->usb_interface_protocol == expected_protocol) { + device_remove_file(&hdev->dev, &dev_attr_version); // Get driver version + device_remove_file(&hdev->dev, &dev_attr_test); // Test mode + device_remove_file(&hdev->dev, &dev_attr_device_type); // Get string of device type + device_remove_file(&hdev->dev, &dev_attr_device_mode); // Get string of device mode + device_remove_file(&hdev->dev, &dev_attr_device_serial); // Get string of device serial + device_remove_file(&hdev->dev, &dev_attr_firmware_version); // Get string of device fw version + + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Custom effect frame + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); // Brightness + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_charging_led_brightness); // Charging effects + device_remove_file(&hdev->dev, &dev_attr_charging_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_charging_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_charging_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_charging_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_charging_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_fast_charging_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_fast_charging_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_fast_charging_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_fast_charging_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_fast_charging_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_fast_charging_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_fully_charged_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_fully_charged_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_fully_charged_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_fully_charged_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_fully_charged_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_fully_charged_matrix_effect_none); + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_MOUSE_DOCK: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + case USB_DEVICE_ID_RAZER_CHROMA_HDK: + case USB_DEVICE_ID_RAZER_CHROMA_BASE: + case USB_DEVICE_ID_RAZER_NOMMO_PRO: + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + case USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA: + case USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA: + case USB_DEVICE_ID_RAZER_RAPTOR_27: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL: + case USB_DEVICE_ID_RAZER_STRIDER_CHROMA: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_CORE: + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + case USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive + device_remove_file(&hdev->dev, &dev_attr_matrix_reactive_trigger); // Reactive trigger + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + device_remove_file(&hdev->dev, &dev_attr_is_mug_present); // Is cup present + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_blinking); // Blinking effect + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); + break; + } + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER: + device_remove_file(&hdev->dev, &dev_attr_reset_channels); + device_remove_file(&hdev->dev, &dev_attr_channel1_size); + device_remove_file(&hdev->dev, &dev_attr_channel2_size); + device_remove_file(&hdev->dev, &dev_attr_channel3_size); + device_remove_file(&hdev->dev, &dev_attr_channel4_size); + device_remove_file(&hdev->dev, &dev_attr_channel5_size); + device_remove_file(&hdev->dev, &dev_attr_channel6_size); + device_remove_file(&hdev->dev, &dev_attr_channel1_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_channel2_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_channel3_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_channel4_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_channel5_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_channel6_led_brightness); + break; + } + } + + hid_hw_stop(hdev); + + kfree(dev); + dev_info(&intf->dev, "Razer Device disconnected\n"); +} + +/** + * Converts interrupt event into PROG1 keypress + * + * Checks if we get the event were after. + * Creates a keypress event of KEY_PROG1 + * + * input_report_key generates an event + * input_sync says were finished, all events are complete. Is useful when setting up other events as they might take multiple statements to complete an event like relative events + * + * data[1] == 0xa0 if mug is present + */ +static int razer_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) +{ + struct razer_accessory_device *device = hid_get_drvdata(hdev); + + if(size == 16 && data[0] == 0x04) { + input_report_key(device->input, KEY_PROG1, 0x01); + input_report_key(device->input, KEY_PROG1, 0x00); + input_sync(device->input); + return 1; + } + + return 0; +} + +/** + * Device ID mapping table + */ +static const struct hid_device_id razer_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_FIREFLY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_FIREFLY_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_STRIDER_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CORE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CORE_X_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CHROMA_MUG) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CHROMA_HDK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CHROMA_BASE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NOMMO_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NOMMO_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MOUSE_DOCK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_RAPTOR_27) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(hid, razer_devices); + +/** + * Describes the contents of the driver + */ +static struct hid_driver razer_accessory_driver = { + .name = "razeraccessory", + .id_table = razer_devices, + .match = razer_accessory_match, + .probe = razer_accessory_probe, + .remove = razer_accessory_disconnect, + .raw_event = razer_raw_event, + .input_mapping = razer_input_mapping, + .input_configured = razer_input_configured +}; + +module_hid_driver(razer_accessory_driver); diff --git a/openrazer/driver/razeraccessory_driver.h b/openrazer/driver/razeraccessory_driver.h new file mode 100644 index 00000000..3c4394a5 --- /dev/null +++ b/openrazer/driver/razeraccessory_driver.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015 Terri Cain + */ + +#ifndef __HID_RAZER_ACCESSORY_H +#define __HID_RAZER_ACCESSORY_H + +#define USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX 0x0068 +#define USB_DEVICE_ID_RAZER_MOUSE_DOCK 0x007E +#define USB_DEVICE_ID_RAZER_CORE 0x0215 +#define USB_DEVICE_ID_RAZER_NOMMO_CHROMA 0x0517 +#define USB_DEVICE_ID_RAZER_NOMMO_PRO 0x0518 +#define USB_DEVICE_ID_RAZER_FIREFLY 0x0C00 +#define USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA 0x0C01 +#define USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED 0x0C02 +#define USB_DEVICE_ID_RAZER_FIREFLY_V2 0x0C04 +#define USB_DEVICE_ID_RAZER_STRIDER_CHROMA 0x0C05 +#define USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_3XL 0x0C06 +#define USB_DEVICE_ID_RAZER_FIREFLY_V2_PRO 0x0C08 +#define USB_DEVICE_ID_RAZER_CHROMA_MUG 0x0F07 +#define USB_DEVICE_ID_RAZER_CHROMA_BASE 0x0F08 +#define USB_DEVICE_ID_RAZER_CHROMA_HDK 0x0F09 +#define USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA 0x0F0D +#define USB_DEVICE_ID_RAZER_RAPTOR_27 0x0F12 +#define USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION 0x0F19 +#define USB_DEVICE_ID_RAZER_CORE_X_CHROMA 0x0F1A +#define USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA 0x0F1D +#define USB_DEVICE_ID_RAZER_CHROMA_ADDRESSABLE_RGB_CONTROLLER 0x0F1F +#define USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA 0x0F20 +#define USB_DEVICE_ID_RAZER_THUNDERBOLT_4_DOCK_CHROMA 0x0F21 +#define USB_DEVICE_ID_RAZER_CHARGING_PAD_CHROMA 0x0F26 +#define USB_DEVICE_ID_RAZER_LAPTOP_STAND_CHROMA_V2 0x0F2B + +#define RAZER_ACCESSORY_WAIT_MIN_US 600 +#define RAZER_ACCESSORY_WAIT_MAX_US 1000 + +#define RAZER_NEW_DEVICE_WAIT_MIN_US 31000 +#define RAZER_NEW_DEVICE_WAIT_MAX_US 31100 + +struct razer_accessory_device { + struct usb_device *usb_dev; + struct input_dev *input; + struct mutex lock; + unsigned char usb_interface_protocol; + + unsigned short usb_vid; + unsigned short usb_pid; + + unsigned char saved_brightness; + + char serial[23]; +}; + +/* + * USB INTERRUPT + * + * */ + +#endif diff --git a/openrazer/driver/razerchromacommon.c b/openrazer/driver/razerchromacommon.c new file mode 100644 index 00000000..ad8dabbf --- /dev/null +++ b/openrazer/driver/razerchromacommon.c @@ -0,0 +1,1590 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Terri Cain + */ + +#include "razerchromacommon.h" + +static unsigned char orochi2011_led[] = { 0x01, 0x00, 0x00, 0x06, 0x48, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x03, 0x05, 0x06, 0x06, 0x10, 0x10, 0x10, 0x10, 0x24, 0x24, 0x4c, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x04, 0x01, 0x04, 0x04, 0x01, 0x01, 0x05, 0x05, 0x01, 0x01, 0x06, 0x31, 0x88, 0x00, 0x07, 0x31, 0x87, 0x00, 0x08, 0x08, 0x01, 0x01, 0x09, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01 }; +static unsigned char orochi2011_dpi[] = { 0x01, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x4c, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +/* + * Standard Device Functions + */ + +/** + * Set what mode the device will operate in. + * + * Currently known modes + * 0x00, 0x00: Normal Mode + * 0x02, 0x00: Unknown Mode + * 0x03, 0x00: Driver Mode + * + * 0x02, 0x00 Will make M1-5 and FN emit normal keystrokes. Some sort of factory test mode. Not recommended to be used. + */ +struct razer_report razer_chroma_standard_set_device_mode(unsigned char mode, unsigned char param) +{ + struct razer_report report = get_razer_report(0x00, 0x04, 0x02); + + if(mode != 0x00 && mode != 0x03) { // Explicitly blocking the 0x02 mode + mode = 0x00; + } + // Only allow 0x00 as param + param = 0x00; + + report.arguments[0] = mode; + report.arguments[1] = param; + + return report; +} + +/** + * Get what mode the device is operating in. + * + * Currently known modes + * 0x00, 0x00: Normal Mode + * 0x02, 0x00: Unknown Mode + * 0x03, 0x00: Driver Mode + * + * 0x02, 0x00 Will make M1-5 and FN emit normal keystrokes. Some sort of factory test mode. Not recommended to be used. + */ +struct razer_report razer_chroma_standard_get_device_mode(void) +{ + return get_razer_report(0x00, 0x84, 0x02); +} + +/** + * Get serial from device + */ +struct razer_report razer_chroma_standard_get_serial(void) +{ + return get_razer_report(0x00, 0x82, 0x16); +} + +/** + * Get firmware version from device + */ +struct razer_report razer_chroma_standard_get_firmware_version(void) +{ + return get_razer_report(0x00, 0x81, 0x02); +} + +/* + * Standard Functions + */ + +/** + * Set the state of an LED on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 03 03 00 010801 | SET LED STATE (VARSTR, GAMEMODE, ON) + * 00 3f 0000 00 03 03 00 010800 | SET LED STATE (VARSTR, GAMEMODE, OFF) + */ +struct razer_report razer_chroma_standard_set_led_state(unsigned char variable_storage, unsigned char led_id, unsigned char led_state) +{ + struct razer_report report = get_razer_report(0x03, 0x00, 0x03); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = clamp_u8(led_state, 0x00, 0x01); + + return report; +} + +struct razer_report razer_chroma_standard_set_led_blinking(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x04, 0x04); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = 0x05; + report.arguments[3] = 0x05; + + return report; +} + +/** + * Get the state of an LED on the device + */ +struct razer_report razer_chroma_standard_get_led_state(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x80, 0x03); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + + return report; +} + +/** + * Set LED RGB parameters + */ +struct razer_report razer_chroma_standard_set_led_rgb(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1) +{ + struct razer_report report = get_razer_report(0x03, 0x01, 0x05); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = rgb1->r; + report.arguments[3] = rgb1->g; + report.arguments[4] = rgb1->b; + + return report; +} + +/** + * Get LED RGB parameters + */ +struct razer_report razer_chroma_standard_get_led_rgb(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x81, 0x05); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + return report; +} + +/** + * Set the effect of an LED on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_set_led_effect(unsigned char variable_storage, unsigned char led_id, unsigned char led_effect) +{ + struct razer_report report = get_razer_report(0x03, 0x02, 0x03); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = clamp_u8(led_effect, 0x00, 0x05); + + return report; +} + +/** + * Get the effect of an LED on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_get_led_effect(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x82, 0x03); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + + return report; +} + +/** + * Set the brightness of an LED on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_set_led_brightness(unsigned char variable_storage, unsigned char led_id, unsigned char brightness) +{ + struct razer_report report = get_razer_report(0x03, 0x03, 0x03); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = brightness; + + return report; +} + +/** + * Get the brightness of an LED on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_get_led_brightness(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x83, 0x03); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + + return report; +} + +/* + * Standard Matrix Effects Functions + */ + +static struct razer_report razer_chroma_standard_matrix_effect_base(unsigned char arg_size, unsigned char effect_id) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, arg_size); + report.arguments[0] = effect_id; + return report; +} + +/** + * Set the effect of the LED matrix to None + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_matrix_effect_none(void) +{ + return razer_chroma_standard_matrix_effect_base(0x01, MATRIX_EFFECT_OFF); +} + +/** + * Set the effect of the LED matrix to Wave + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_matrix_effect_wave(unsigned char wave_direction) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x02, MATRIX_EFFECT_WAVE); + report.arguments[1] = clamp_u8(wave_direction, 0x01, 0x02); + + return report; +} + +/** + * Set the effect of the LED matrix to Spectrum + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_matrix_effect_spectrum(void) +{ + return razer_chroma_standard_matrix_effect_base(0x01, MATRIX_EFFECT_SPECTRUM); +} + +/** + * Set the effect of the LED matrix to Reactive + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_matrix_effect_reactive(unsigned char speed, struct razer_rgb *rgb1) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x05, MATRIX_EFFECT_REACTIVE); + report.arguments[1] = clamp_u8(speed, 0x01, 0x04); // Time + report.arguments[2] = rgb1->r; /*rgb color definition*/ + report.arguments[3] = rgb1->g; + report.arguments[4] = rgb1->b; + + return report; +} + +/** + * Set the effect of the LED matrix to Static + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_matrix_effect_static(struct razer_rgb *rgb1) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x04, MATRIX_EFFECT_STATIC); + report.arguments[1] = rgb1->r; /*rgb color definition*/ + report.arguments[2] = rgb1->g; + report.arguments[3] = rgb1->b; + + return report; +} + +/** + * Set the effect of the LED matrix to Starlight + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_matrix_effect_starlight_single(unsigned char speed, struct razer_rgb *rgb1) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x01, MATRIX_EFFECT_STARLIGHT); + + report.arguments[1] = 0x01; // Type one color + report.arguments[2] = clamp_u8(speed, 0x01, 0x03); // Speed + + report.arguments[3] = rgb1->r; // Red 1 + report.arguments[4] = rgb1->g; // Green 1 + report.arguments[5] = rgb1->b; // Blue 1 + + // For now haven't seen any chroma using this, seen the extended version + report.arguments[6] = 0x00; // Red 2 + report.arguments[7] = 0x00; // Green 2 + report.arguments[8] = 0x00; // Blue 2 + + return report; +} + +/** + * Set the effect of the LED matrix to Starlight + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_standard_matrix_effect_starlight_dual(unsigned char speed, struct razer_rgb *rgb1, struct razer_rgb *rgb2) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x01, MATRIX_EFFECT_STARLIGHT); + + report.arguments[1] = 0x02; // Type two color + report.arguments[2] = clamp_u8(speed, 0x01, 0x03); // Speed + + report.arguments[3] = rgb1->r; // Red 1 + report.arguments[4] = rgb1->g; // Green 1 + report.arguments[5] = rgb1->b; // Blue 1 + + report.arguments[6] = rgb2->r; // Red 2 + report.arguments[7] = rgb2->g; // Green 2 + report.arguments[8] = rgb2->b; // Blue 2 + + return report; +} + +struct razer_report razer_chroma_standard_matrix_effect_starlight_random(unsigned char speed) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x01, MATRIX_EFFECT_STARLIGHT); + + report.arguments[1] = 0x03; // Type random color + report.arguments[2] = clamp_u8(speed, 0x01, 0x03); // Speed + + return report; +} + +/** + * Set the device to "Breathing" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * ?? + * ?? + * ?? + */ +struct razer_report razer_chroma_standard_matrix_effect_breathing_random(void) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x08, MATRIX_EFFECT_BREATHING); + report.arguments[1] = 0x03; // Breathing type + + return report; +} +struct razer_report razer_chroma_standard_matrix_effect_breathing_single(struct razer_rgb *rgb1) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x08, MATRIX_EFFECT_BREATHING); + report.arguments[1] = 0x01; // Breathing type + report.arguments[2] = rgb1->r; + report.arguments[3] = rgb1->g; + report.arguments[4] = rgb1->b; + + return report; +} +struct razer_report razer_chroma_standard_matrix_effect_breathing_dual(struct razer_rgb *rgb1, struct razer_rgb *rgb2) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x08, MATRIX_EFFECT_BREATHING); + report.arguments[1] = 0x02; // Breathing type + report.arguments[2] = rgb1->r; + report.arguments[3] = rgb1->g; + report.arguments[4] = rgb1->b; + report.arguments[5] = rgb2->r; + report.arguments[6] = rgb2->g; + report.arguments[7] = rgb2->b; + + return report; +} + +/** + * Set the device to "Custom" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * ?? + * + * Apparently Ultimate2016, Stealth and Stealth2016 need frame id to be 0x00, I don't think it's needed (depending on set_custom_frame) + */ +struct razer_report razer_chroma_standard_matrix_effect_custom_frame(unsigned char variable_storage) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x02, MATRIX_EFFECT_CUSTOMFRAME); + report.arguments[1] = variable_storage; // Data frame ID + + return report; +} + +/** + * Set the RGB or a row + * + * Start and stop columns are inclusive + * + * This sets the colour of a row on the keyboard. Takes in an array of RGB bytes. + * The mappings below are correct for the BlackWidow Chroma. The BlackWidow Ultimate 2016 + * contains LEDs under the spacebar and the FN key so there will be changes once I get the + * hardware. + * + * Row 0: + * 0 Unused + * 1 ESC + * 2 Unused + * 3-14 F1-F12 + * 15-17 PrtScr, ScrLk, Pause + * 18-19 Unused + * 20 Razer Logo + * 21 Unused + * + * Row 1: + * 0-21 M1 -> NP Minus + * + * Row 2: + * 0-13 M2 -> Right Square Bracket ] + * 14 Unused + * 15-21 Delete -> NP Plus + * + * Row 3: + * 0-14 M3 -> Return + * 15-17 Unused + * 18-20 NP4 -> NP6 + * + * Row 4: + * 0-12 M4 -> Forward Slash / + * 13 Unused + * 14 Right Shift + * 15 Unused + * 16 Up Arrow Key + * 17 Unused + * 18-21 NP1 -> NP Enter + * + * Row 5: + * 0-3 M5 -> Alt + * 4-10 Unused + * 11 Alt GR + * 12 Unused + * 13-17 Context Menu Key -> Right Arrow Key + * 18 Unused + * 19-20 NP0 -> NP. + * 21 Unused + */ +struct razer_report razer_chroma_standard_matrix_set_custom_frame(unsigned char row_index, unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data) +{ + const size_t start_arg_offset = 4; + struct razer_report report = {0}; + size_t row_length = (size_t) (((stop_col + 1) - start_col) * 3); + + if (row_length > sizeof(report.arguments) - start_arg_offset) { + printk(KERN_ALERT "razerchroma: RGB data too long\n"); + row_length = 0; + } + + report = get_razer_report(0x03, 0x0B, 0x46); // In theory should be able to leave data size at max as we have start/stop + + // printk(KERN_ALERT "razerkbd: Row ID: %d, Start: %d, Stop: %d, row length: %d\n", row_index, start_col, stop_col, (unsigned char)row_length); + + report.arguments[0] = 0xFF; // Frame ID + report.arguments[1] = row_index; + report.arguments[2] = start_col; + report.arguments[3] = stop_col; + memcpy(&report.arguments[4], rgb_data, row_length); + + return report; +} + +/* + * Extended Matrix Effects + */ + +/** + * Sets up the extended matrix effect payload + */ +static struct razer_report razer_chroma_extended_matrix_effect_base(unsigned char arg_size, unsigned char variable_storage, unsigned char led_id, unsigned char effect_id) +{ + struct razer_report report = get_razer_report(0x0F, 0x02, arg_size); + + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = effect_id; // Effect ID + + return report; +} + +/** + * Set the device to "None" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 06 0f 02 010500000000 | SET LED MATRIX Effect (VARSTR, Backlight, None 0x00, 0x000000) + */ +struct razer_report razer_chroma_extended_matrix_effect_none(unsigned char variable_storage, unsigned char led_id) +{ + return razer_chroma_extended_matrix_effect_base(0x06, variable_storage, led_id, 0x00); +} + +/** + * Set the device to "Static" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 09 0f 02 010501000001ff0000 | SET LED MATRIX Effect (VARSTR, Backlight, Static 0x01, ? 0x000001, RGB 0xFF0000) + * 00 3f 0000 00 09 0f 02 01050100000100ff00 | SET LED MATRIX Effect (VARSTR, Backlight, Static 0x01, ? 0x000001, RGB 0x00FF00) + * 00 3f 0000 00 09 0f 02 010501000001008000 | SET LED MATRIX Effect (VARSTR, Backlight, Static 0x01, ? 0x000001, RGB 0x008000) + */ +struct razer_report razer_chroma_extended_matrix_effect_static(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x09, variable_storage, led_id, 0x01); + + report.arguments[5] = 0x01; + report.arguments[6] = rgb->r; + report.arguments[7] = rgb->g; + report.arguments[8] = rgb->b; + return report; +} + +/** + * Set the device to "Wave" effect + * + * Seems like direction is now 0x00, 0x01 for Left/Right, used to be 0x01, 0x02 + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 06 0f 02 010504002800 | SET LED MATRIX Effect (VARSTR, Backlight, Wave 0x04, Dir 0x00, ? 0x2800) + * 00 3f 0000 00 06 0f 02 010504012800 | SET LED MATRIX Effect (VARSTR, Backlight, Wave 0x04, Dir 0x01, ? 0x2800) + */ +struct razer_report razer_chroma_extended_matrix_effect_wave(unsigned char variable_storage, unsigned char led_id, unsigned char direction) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x06, variable_storage, led_id, 0x04); + + // Some devices use values 0x00, 0x01 + // Others use values 0x01, 0x02 + direction = clamp_u8(direction, 0x00, 0x02); + + // Razer has also added a "Fast Wave" effect for at least one device + // which uses the same effect command but a speed parameter of 0x10 + report.arguments[3] = direction; + report.arguments[4] = 0x28; // Speed, lower values are faster + return report; +} + +/** + * Set the device to "Starlight" effect + * + * Speed is 0x01 - 0x03 + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 06 0f 02 010507000100 | SET LED MATRIX Effect (VARSTR, Backlight, Starlight 0x07, ? 0x00, Speed 0x01, Colours 0x00) + * 00 3f 0000 00 06 0f 02 010507000200 | SET LED MATRIX Effect (VARSTR, Backlight, Starlight 0x07, ? 0x00, Speed 0x02, Colours 0x00) + * 00 3f 0000 00 06 0f 02 010507000300 | SET LED MATRIX Effect (VARSTR, Backlight, Starlight 0x07, ? 0x00, Speed 0x03, Colours 0x00) + * 00 3f 0000 00 09 0f 02 010507000301ff0000 | SET LED MATRIX Effect (VARSTR, Backlight, Starlight 0x07, ? 0x00, Speed 0x03, Colours 0x01, RGB 0xFF0000) + * 00 3f 0000 00 0c 0f 02 010507000302ff000000ff00 | SET LED MATRIX Effect (VARSTR, Backlight, Starlight 0x07, ? 0x00, Speed 0x03, Colours 0x02, RGB 0xFF0000, RGB 0x00FF00) + */ +struct razer_report razer_chroma_extended_matrix_effect_starlight_random(unsigned char variable_storage, unsigned char led_id, unsigned char speed) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x06, variable_storage, led_id, 0x07); + + speed = clamp_u8(speed, 0x01, 0x03); + + report.arguments[4] = speed; + return report; +} +struct razer_report razer_chroma_extended_matrix_effect_starlight_single(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x09, variable_storage, led_id, 0x07); + + speed = clamp_u8(speed, 0x01, 0x03); + + report.arguments[4] = speed; + report.arguments[5] = 0x01; + report.arguments[6] = rgb1->r; + report.arguments[7] = rgb1->g; + report.arguments[8] = rgb1->b; + + return report; +} +struct razer_report razer_chroma_extended_matrix_effect_starlight_dual(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1, struct razer_rgb *rgb2) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x0C, variable_storage, led_id, 0x07); + + speed = clamp_u8(speed, 0x01, 0x03); + + report.arguments[4] = speed; + report.arguments[5] = 0x02; + report.arguments[6] = rgb1->r; + report.arguments[7] = rgb1->g; + report.arguments[8] = rgb1->b; + report.arguments[9] = rgb2->r; + report.arguments[10] = rgb2->g; + report.arguments[11] = rgb2->b; + + return report; +} + +/** + * Set the device to "Spectrum" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 06 0f 02 010503000000 | SET LED MATRIX Effect (VARSTR, Backlight, Spectrum 0x03, 0x000000) + */ +struct razer_report razer_chroma_extended_matrix_effect_spectrum(unsigned char variable_storage, unsigned char led_id) +{ + return razer_chroma_extended_matrix_effect_base(0x06, variable_storage, led_id, 0x03); +} + +/** + * Set the device to "Wheel" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 1f 0000 00 06 0f 02 01050a022800 | SET LED MATRIX Effect (VARSTR, Backlight, Wheel 0x0A, Dir 0x02, Speed 0x28, ? 0x00) + */ +struct razer_report razer_chroma_extended_matrix_effect_wheel(unsigned char variable_storage, unsigned char led_id, unsigned char direction) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x06, variable_storage, led_id, 0x0a); + + // BlackWidow V4 Pro uses 0x01 and 0x02 for directions + // Commands with direction 0x00 seem to be ignored + direction = clamp_u8(direction, 0x01, 0x02); + + report.arguments[3] = direction; + report.arguments[4] = 0x28; // Speed, lower values are faster + + return report; +} + +/** + * Set the device to "Reactive" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 09 0f 02 010505000101ffff00 | SET LED MATRIX Effect (VARSTR, Backlight, Reactive 0x05, ? 0x00, Speed 0x01, Colours 0x01, RGB 0xFFFF00) + * 00 3f 0000 00 09 0f 02 010505000101ff0000 | SET LED MATRIX Effect (VARSTR, Backlight, Reactive 0x05, ? 0x00, Speed 0x02, Colours 0x01, RGB 0xFF0000) + * 00 3f 0000 00 09 0f 02 010505000301ff0000 | SET LED MATRIX Effect (VARSTR, Backlight, Reactive 0x05, ? 0x00, Speed 0x03, Colours 0x01, RGB 0xFF0000) + * 00 3f 0000 00 09 0f 02 010505000401ff0000 | SET LED MATRIX Effect (VARSTR, Backlight, Reactive 0x05, ? 0x00, Speed 0x04, Colours 0x01, RGB 0xFF0000) + */ +struct razer_report razer_chroma_extended_matrix_effect_reactive(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x09, variable_storage, led_id, 0x05); + + speed = clamp_u8(speed, 0x01, 0x04); + + report.arguments[4] = speed; + report.arguments[5] = 0x01; + report.arguments[6] = rgb->r; + report.arguments[7] = rgb->g; + report.arguments[8] = rgb->b; + + return report; +} + +/** + * Set the device to "Breathing" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 09 0f 02 01050201000100ff00 | SET LED MATRIX Effect (VARSTR, Backlight, Breathing 0x02, Colours 0x01, ? 0x00, Colours 0x01, RGB 0x00FF00) + * 00 3f 0000 00 0c 0f 02 01050202000200ff00ff0000 | SET LED MATRIX Effect (VARSTR, Backlight, Breathing 0x02, Colours 0x02, ? 0x00, Colours 0x02, RGB 0x00FF00, RGB 0xFF0000) + * 00 3f 0000 00 06 0f 02 010502000000 | SET LED MATRIX Effect (VARSTR, Backlight, Breathing 0x02, Colours 0x00, ? 0x0000) + */ +struct razer_report razer_chroma_extended_matrix_effect_breathing_random(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x06, variable_storage, led_id, 0x02); + return report; +} +struct razer_report razer_chroma_extended_matrix_effect_breathing_single(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x09, variable_storage, led_id, 0x02); + + report.arguments[3] = 0x01; + report.arguments[5] = 0x01; + + report.arguments[6] = rgb1->r; + report.arguments[7] = rgb1->g; + report.arguments[8] = rgb1->b; + + return report; +} +struct razer_report razer_chroma_extended_matrix_effect_breathing_dual(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1, struct razer_rgb *rgb2) +{ + struct razer_report report = razer_chroma_extended_matrix_effect_base(0x0C, variable_storage, led_id, 0x02); + + report.arguments[3] = 0x02; + report.arguments[5] = 0x02; + + report.arguments[6] = rgb1->r; + report.arguments[7] = rgb1->g; + report.arguments[8] = rgb1->b; + report.arguments[9] = rgb2->r; + report.arguments[10] = rgb2->g; + report.arguments[11] = rgb2->b; + + return report; +} + +/** + * Set the device to "Custom" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 0c 0f 02 000008000000000000000000 | DRAW LED MATRIX Frame + */ +struct razer_report razer_chroma_extended_matrix_effect_custom_frame(void) +{ + return razer_chroma_extended_matrix_effect_base(0x0C, 0x00, 0x00, 0x08); +} + +/** + * Set the device brightness + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 03 0f 04 0104b7 + */ +struct razer_report razer_chroma_extended_matrix_brightness(unsigned char variable_storage, unsigned char led_id, unsigned char brightness) +{ + struct razer_report report = get_razer_report(0x0F, 0x04, 0x03); + + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = brightness; + + return report; +} + +/** + * Get the device brightness + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 03 0f 84 0104 + */ +struct razer_report razer_chroma_extended_matrix_get_brightness(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x0F, 0x84, 0x03); + + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + + return report; +} + +/** + * Set the RGB or a row + * + * Start and stop columns are inclusive + */ +struct razer_report razer_chroma_extended_matrix_set_custom_frame(unsigned char row_index, unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data) +{ + return razer_chroma_extended_matrix_set_custom_frame2(row_index, start_col, stop_col, rgb_data, 0x47); +} + +struct razer_report razer_chroma_extended_matrix_set_custom_frame2(unsigned char row_index, unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data, size_t packetLength) +{ + const size_t start_arg_offset = 5; + size_t data_length = 0; + struct razer_report report = {0}; + size_t row_length = (size_t) (((stop_col + 1) - start_col) * 3); + + if (row_length > sizeof(report.arguments) - start_arg_offset) { + printk(KERN_ALERT "razerchroma: RGB data too long\n"); + row_length = 0; + } + + // Some devices need a specific packet length, most devices are happy with 0x47 + // e.g. the Mamba Elite needs a "row_length + 5" packet length + data_length = (packetLength != 0) ? packetLength : row_length + 5; + report = get_razer_report(0x0F, 0x03, data_length); + + // printk(KERN_ALERT "razerkbd: Row ID: %d, Start: %d, Stop: %d, row length: %d\n", row_index, start_col, stop_col, (unsigned char)row_length); + + report.arguments[2] = row_index; + report.arguments[3] = start_col; + report.arguments[4] = stop_col; + memcpy(&report.arguments[5], rgb_data, row_length); + + return report; +} + +/* + * Extended Matrix Effects (Mouse) + */ +/** + * Sets up the extended matrix effect payload for mouse devices + */ +static struct razer_report razer_chroma_mouse_extended_matrix_effect_base(unsigned char arg_size, unsigned char variable_storage, unsigned char led_id, unsigned char effect_id) +{ + struct razer_report report = get_razer_report(0x03, 0x0D, arg_size); + + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = effect_id; // Effect ID + + return report; +} + +/** + * Set the device to "None" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * * 00 3f 0000 00 03 03 0d 010100 | SET Extended Matrix Effect (VARSTORE, LOGO_LED, OFF) + */ +struct razer_report razer_chroma_mouse_extended_matrix_effect_none(unsigned char variable_storage, unsigned char led_id) +{ + return razer_chroma_mouse_extended_matrix_effect_base(0x03, variable_storage, led_id, 0x00); +} + +/** + * Set the device to "Static" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 06 03 0d 010106 00ff00 | SET Extended Matrix Effect (VARSTORE, SCROLL_WHEEL, STATIC, RGB) + */ +struct razer_report razer_chroma_mouse_extended_matrix_effect_static(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb) +{ + struct razer_report report = razer_chroma_mouse_extended_matrix_effect_base(0x06, variable_storage, led_id, 0x06); + + report.arguments[3] = rgb->r; + report.arguments[4] = rgb->g; + report.arguments[5] = rgb->b; + return report; +} + +/** + * Set the device to "Spectrum" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 03 03 0d 010104 | SET Extended Matrix Effect (VARSTORE, LOGO_LED, SPECTRUM) + */ +struct razer_report razer_chroma_mouse_extended_matrix_effect_spectrum(unsigned char variable_storage, unsigned char led_id) +{ + return razer_chroma_mouse_extended_matrix_effect_base(0x03, variable_storage, led_id, 0x04); +} + +/** + * Set the device to "Reactive" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 07 03 0d 010102 0300ff00 | SET Extended Matrix Effect (VARSTORE, SCROLL_WHEEL, REACTIVE, TIME, RGB) + * 00 3f 0000 00 07 03 0d 010102 0200ff00 | SET Extended Matrix Effect (VARSTORE, SCROLL_WHEEL, REACTIVE, TIME, RGB) + * 00 3f 0000 00 07 03 0d 010102 0100ff00 | SET Extended Matrix Effect (VARSTORE, SCROLL_WHEEL, REACTIVE, TIME, RGB) + */ +struct razer_report razer_chroma_mouse_extended_matrix_effect_reactive(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb) +{ + struct razer_report report = razer_chroma_mouse_extended_matrix_effect_base(0x07, variable_storage, led_id, 0x02); + + speed = clamp_u8(speed, 0x01, 0x04); + + report.arguments[3] = speed; + report.arguments[4] = rgb->r; + report.arguments[5] = rgb->g; + report.arguments[6] = rgb->b; + + return report; +} + +/** + * Set the device to "Breathing" effect + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 3f 0000 00 0a 03 0d 010103 0100ff00000000 | SET Extended Matrix Effect (VARSTORE, SCROLL_WHEEL, BREATHING, single, RGB, RGB-none) + * 00 3f 0000 00 0a 03 0d 010103 0200ff00ff0000 | SET Extended Matrix Effect (VARSTORE, SCROLL_WHEEL, BREATHING, dual, RGB, RGB) + * 00 3f 0000 00 0a 03 0d 010103 03000000000000 | SET Extended Matrix Effect (VARSTORE, SCROLL_WHEEL, BREATHING, random, RGB-none, RGB-none) + */ +struct razer_report razer_chroma_mouse_extended_matrix_effect_breathing_random(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = razer_chroma_mouse_extended_matrix_effect_base(0x0A, variable_storage, led_id, 0x03); + + report.arguments[3] = 0x03; + + return report; +} +struct razer_report razer_chroma_mouse_extended_matrix_effect_breathing_single(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1) +{ + struct razer_report report = razer_chroma_mouse_extended_matrix_effect_base(0x0A, variable_storage, led_id, 0x03); + + report.arguments[3] = 0x01; + + report.arguments[4] = rgb1->r; + report.arguments[5] = rgb1->g; + report.arguments[6] = rgb1->b; + + return report; +} +struct razer_report razer_chroma_mouse_extended_matrix_effect_breathing_dual(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1, struct razer_rgb *rgb2) +{ + struct razer_report report = razer_chroma_mouse_extended_matrix_effect_base(0x0A, variable_storage, led_id, 0x03); + + report.arguments[3] = 0x02; + + report.arguments[4] = rgb1->r; + report.arguments[5] = rgb1->g; + report.arguments[6] = rgb1->b; + + report.arguments[7] = rgb2->r; + report.arguments[8] = rgb2->g; + report.arguments[9] = rgb2->b; + + return report; +} + +/* + * Misc Functions + */ +/** + * Toggled whether F1-12 act as F1-12 or if they act as the function options (without Fn pressed) + * + * If 0 should mean that the F-keys work as normal F-keys + * If 1 should mean that the F-keys act as if the FN key is held + */ +struct razer_report razer_chroma_misc_fn_key_toggle(unsigned char state) +{ + struct razer_report report = get_razer_report(0x02, 0x06, 0x02); + report.arguments[0] = 0x00; // ?? Variable storage maybe + report.arguments[1] = clamp_u8(state, 0x00, 0x01); // State + + return report; +} + +/** + * Set the keyswitch optimization on the device (first of two commands) + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 1f 0000 00 04 02 02 001400280000 | SET KEY OPTIMIZATION STATE (TYPING SET) + * 00 1f 0000 00 04 02 02 000000000000 | SET KEY OPTIMIZATION STATE (GAMING SET) + */ +struct razer_report razer_chroma_misc_set_keyswitch_optimization_command1(unsigned char optimization_mode) +{ + struct razer_report report = get_razer_report(0x02, 0x02, 0x04); // class, id, data size + + // 0x00 -> Typing (Set) + // 0x01 -> Gaming (Set) - Same report, doesn't include any arguments + if(optimization_mode == 0x00) { + report.arguments[0] = 0x00; + report.arguments[1] = 0x14; + report.arguments[2] = 0x00; + report.arguments[3] = 0x28; + report.arguments[4] = 0x00; + } + + return report; +} + +/** +* Set the keyswitch optimization on the device (second of two commands) + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 1f 0000 00 05 02 15 010014002800 | SET KEY OPTIMIZATION STATE (TYPING VARSTORE) ???? + * 00 1f 0000 00 05 02 15 010000000000 | SET KEY OPTIMIZATION STATE (GAMING VARSTORE) ???? + */ +struct razer_report razer_chroma_misc_set_keyswitch_optimization_command2(unsigned char optimization_mode) +{ + struct razer_report report = get_razer_report(0x02, 0x15, 0x05); // class, id, data size + + // 0x00 -> Typing (Store) + // 0x01 -> Gaming (Store) + switch(optimization_mode) { + case 0x00: + report.arguments[0] = 0x01; + report.arguments[1] = 0x00; + report.arguments[2] = 0x14; + report.arguments[3] = 0x00; + report.arguments[4] = 0x28; + report.arguments[5] = 0x00; + break; + case 0x01: + report.arguments[0] = 0x01; + break; + } + + return report; +} + +/** + * Get the keyswitch optimization on the device + * + * Identifiers in arg[1] and arg[3] + * + * 0x00<->0x14 is in arg[1] + * 0x00<->0x28 is in arg[3] + */ +struct razer_report razer_chroma_misc_get_keyswitch_optimization(void) +{ + struct razer_report report = get_razer_report(0x02, 0x82, 0x04); // class, id, data size + + return report; +} + +/** + * Set the brightness of an LED on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_misc_set_blade_brightness(unsigned char brightness) +{ + struct razer_report report = get_razer_report(0x0E, 0x04, 0x02); + report.arguments[0] = 0x01; + report.arguments[1] = brightness; + + return report; +} + +/** + * Get the brightness of an LED on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * ? TODO fill this + */ +struct razer_report razer_chroma_misc_get_blade_brightness(void) +{ + struct razer_report report = get_razer_report(0x0E, 0x84, 0x02); + report.arguments[0] = 0x01; + + return report; +} + +/** + * Sets custom frame for the firefly + */ +struct razer_report razer_chroma_misc_one_row_set_custom_frame(unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data) // TODO recheck custom frame hex +{ + const size_t start_arg_offset = 2; + struct razer_report report = get_razer_report(0x03, 0x0C, 0x32); + size_t row_length = (size_t) (((stop_col + 1) - start_col) * 3); + + if (row_length > sizeof(report.arguments) - start_arg_offset) { + printk(KERN_ALERT "razerchroma: RGB data too long\n"); + row_length = 0; + } + + report.arguments[0] = start_col; + report.arguments[1] = stop_col; + + memcpy(&report.arguments[2], rgb_data, row_length); + + return report; +} + +/** + * Trigger reactive on Firefly + */ +struct razer_report razer_chroma_misc_matrix_reactive_trigger(void) +{ + struct razer_report report = razer_chroma_standard_matrix_effect_base(0x05, MATRIX_EFFECT_REACTIVE); + report.arguments[1] = 0; // this speed triggers reactive + report.arguments[2] = 0; + report.arguments[3] = 0; + report.arguments[4] = 0; + + return report; +} + +/** + * Gets battery level + * + * 0->255 is in arg[1] + */ +struct razer_report razer_chroma_misc_get_battery_level(void) +{ + return get_razer_report(0x07, 0x80, 0x02); +} + +/** + * Gets charging status + * + * 0->1 is in arg[1] + */ +struct razer_report razer_chroma_misc_get_charging_status(void) +{ + return get_razer_report(0x07, 0x84, 0x02); +} + +/** + * Set the charging effect, think if I remember correctly, it's either static colour, or "whatever the mouse was last on" + */ +struct razer_report razer_chroma_misc_set_dock_charge_type(unsigned char charge_type) +{ + struct razer_report report = get_razer_report(0x03, 0x10, 0x01); + report.arguments[0] = clamp_u8(charge_type, 0x00, 0x01); + + return report; +} + +/** + * Get the polling rate from the device + * + * Identifier is in arg[0] + * + * 0x01 = 1000Hz + * 0x02 = 500Hz + * 0x08 = 125Hz + */ +struct razer_report razer_chroma_misc_get_polling_rate(void) +{ + return get_razer_report(0x00, 0x85, 0x01); +} + +/** + * Set the polling rate of the device + * + * 0x01 = 1000Hz + * 0x02 = 500Hz + * 0x08 = 125Hz + */ +struct razer_report razer_chroma_misc_set_polling_rate(unsigned short polling_rate) +{ + struct razer_report report = get_razer_report(0x00, 0x05, 0x01); + + switch(polling_rate) { + case 1000: + report.arguments[0] = 0x01; + break; + case 500: + report.arguments[0] = 0x02; + break; + case 125: + report.arguments[0] = 0x08; + break; + default: // 500Hz + report.arguments[0] = 0x02; + break; + } + + return report; +} + +/** + * Get the polling rate from the device + * + * Identifier is in arg[1] + * + * 0x01 = 8000Hz + * 0x02 = 4000Hz + * 0x04 = 2000Hz + * 0x08 = 1000Hz + * 0x10 = 500Hz + * 0x40 = 125Hz + */ +struct razer_report razer_chroma_misc_get_polling_rate2(void) +{ + return get_razer_report(0x00, 0xC0, 0x01); +} + +/** + * Set the polling rate of the device + * + * 0x40 = 125 Hz + * 0x10 = 500 Hz + * 0x08 = 1000 Hz + * 0x04 = 2000 Hz + * 0x02 = 4000 Hz + * 0x01 = 8000 Hz + */ +struct razer_report razer_chroma_misc_set_polling_rate2(unsigned short polling_rate, unsigned short argument) +{ + struct razer_report report = get_razer_report(0x00, 0x40, 0x02); + + report.arguments[0] = argument; // For some devices Razer sends each request once with 0x00 and once with 0x01 - maybe varstore? + switch(polling_rate) { + case 8000: + report.arguments[1] = 0x01; + break; + case 4000: + report.arguments[1] = 0x02; + break; + case 2000: + report.arguments[1] = 0x04; + break; + case 1000: + report.arguments[1] = 0x08; + break; + case 500: + report.arguments[1] = 0x10; + break; + case 250: + report.arguments[1] = 0x20; + break; + case 125: + report.arguments[1] = 0x40; + break; + default: // 500Hz + report.arguments[1] = 0x10; + break; + } + + return report; +} + +/** + * Get brightness of charging dock + */ +struct razer_report razer_chroma_misc_get_dock_brightness(void) +{ + return get_razer_report(0x07, 0x82, 0x01); + +} + +/** + * Set brightness of charging dock + */ +struct razer_report razer_chroma_misc_set_dock_brightness(unsigned char brightness) +{ + struct razer_report report = get_razer_report(0x07, 0x02, 0x01); + report.arguments[0] = brightness; + + return report; +} + +/** + * Set the DPI of the device + */ +struct razer_report razer_chroma_misc_set_dpi_xy(unsigned char variable_storage, unsigned short dpi_x,unsigned short dpi_y) +{ + struct razer_report report = get_razer_report(0x04, 0x05, 0x07); + + // Keep the DPI within bounds + dpi_x = clamp_u16(dpi_x, 100, 35000); + dpi_y = clamp_u16(dpi_y, 100, 35000); + + report.arguments[0] = VARSTORE; + + report.arguments[1] = (dpi_x >> 8) & 0x00FF; + report.arguments[2] = dpi_x & 0x00FF; + report.arguments[3] = (dpi_y >> 8) & 0x00FF; + report.arguments[4] = dpi_y & 0x00FF; + report.arguments[5] = 0x00; + report.arguments[6] = 0x00; + + return report; +} + +/** + * Get the DPI of the device + */ +struct razer_report razer_chroma_misc_get_dpi_xy(unsigned char variable_storage) +{ + struct razer_report report = get_razer_report(0x04, 0x85, 0x07); + + report.arguments[0] = variable_storage; + + return report; +} + +/** + * Set the DPI of the device (Some stupid turd scaled 5600 dpi into a single byte) + */ +struct razer_report razer_chroma_misc_set_dpi_xy_byte(unsigned char dpi_x,unsigned char dpi_y) +{ + struct razer_report report = get_razer_report(0x04, 0x01, 0x03); + + report.arguments[0] = dpi_x; + report.arguments[1] = dpi_y; + report.arguments[2] = 0x00; + + return report; +} + +/** + * Get the DPI of the device (Some stupid turd scaled 5600 dpi into a single byte) + */ +struct razer_report razer_chroma_misc_get_dpi_xy_byte(void) +{ + struct razer_report report = get_razer_report(0x04, 0x81, 0x03); + + return report; +} + +/** + * Set DPI stages of the device. + * + * count is the number of stages to set. + * active_stage selected stage number. + * dpi is an array of size 2 * count containing pairs of dpi x and dpi y + * values, one pair for each stage. + * + * E.g.: + * count = 3 + * active_stage = 1 + * dpi = [ 800, 800, 1800, 1800, 3200, 3200] + * | stage 1*| stage 2 | stage 3 | + */ +struct razer_report razer_chroma_misc_set_dpi_stages(unsigned char variable_storage, unsigned char count, unsigned char active_stage, const unsigned short *dpi) +{ + struct razer_report report = get_razer_report(0x04, 0x06, 0x26); + unsigned int offset; + unsigned int i; + + report.arguments[0] = variable_storage; + report.arguments[1] = active_stage; + report.arguments[2] = count; + + offset = 3; + for (i = 0; i < count; i++) { + // Stage number + report.arguments[offset++] = i; + + // DPI X + report.arguments[offset++] = (dpi[0] >> 8) & 0x00FF; + report.arguments[offset++] = dpi[0] & 0x00FF; + + // DPI Y + report.arguments[offset++] = (dpi[1] >> 8) & 0x00FF; + report.arguments[offset++] = dpi[1] & 0x00FF; + + // Reserved + report.arguments[offset++] = 0; + report.arguments[offset++] = 0; + + dpi += 2; + } + + return report; +} + +/** + * Get the DPI stages of the device + */ +struct razer_report razer_chroma_misc_get_dpi_stages(unsigned char variable_storage) +{ + struct razer_report report = get_razer_report(0x04, 0x86, 0x26); + + report.arguments[0] = variable_storage; + + return report; +} + +/** + * Get device idle time + */ +struct razer_report razer_chroma_misc_get_idle_time(void) +{ + return get_razer_report(0x07, 0x83, 0x02); +} + +/** + * Set device idle time + * + * Device will go into powersave after this time. + * + * Idle time is in seconds, must be between 60sec-900sec + */ +struct razer_report razer_chroma_misc_set_idle_time(unsigned short idle_time) +{ + struct razer_report report = get_razer_report(0x07, 0x03, 0x02); + + // Keep the idle time within bounds + idle_time = clamp_u16(idle_time, 60, 900); + + report.arguments[0] = (idle_time >> 8) & 0x00FF; + report.arguments[1] = idle_time & 0x00FF; + + return report; +} + +/** + * Get low battery threshold + */ +struct razer_report razer_chroma_misc_get_low_battery_threshold(void) +{ + return get_razer_report(0x07, 0x81, 0x01); +} + +/** + * Set low battery threshold + * + * 0x3F = 25% + * 0x26 = 15% + * 0x0C = 5% + */ +struct razer_report razer_chroma_misc_set_low_battery_threshold(unsigned char battery_threshold) +{ + struct razer_report report = get_razer_report(0x07, 0x01, 0x01); + + // Keep the battery threshold within bounds + battery_threshold = clamp_u8(battery_threshold, 0x0C, 0x3F); + + report.arguments[0] = battery_threshold; + + return report; +} + +struct razer_report razer_chroma_misc_set_orochi2011_led(unsigned char led_bitfield) +{ + struct razer_report report = {0}; + memcpy(&report, &orochi2011_led, sizeof(orochi2011_led)); + + report.arguments[1] = led_bitfield; + + return report; +} + +struct razer_report razer_chroma_misc_set_orochi2011_poll_dpi(unsigned short poll_rate, unsigned char dpi_x, unsigned char dpi_y) +{ + struct razer_report report = {0}; + memcpy(&report, &orochi2011_dpi, sizeof(orochi2011_dpi)); + + switch(poll_rate) { + case 1000: + poll_rate = 0x01; + break; + case 500: + poll_rate = 0x02; + break; + case 125: + poll_rate = 0x08; + break; + default: // 500Hz + poll_rate = 0x02; + break; + } + + report.arguments[1] = poll_rate; + + report.arguments[3] = clamp_u8(dpi_x, 0x15, 0x9C); + report.arguments[4] = clamp_u8(dpi_y, 0x15, 0x9C); + + return report; +} + +/** + * Set the Naga Trinity to "Static" effect + */ +struct razer_report razer_naga_trinity_effect_static(struct razer_rgb *rgb) +{ + struct razer_report report = get_razer_report(0x0f, 0x03, 0x0e); + + report.arguments[0] = 0x00; // Variable storage + report.arguments[1] = 0x00; // LED ID + report.arguments[2] = 0x00; // Unknown + report.arguments[3] = 0x00; // Unknown + report.arguments[4] = 0x02; // Effect ID + report.arguments[5] = rgb->r; // RGB 3x + report.arguments[6] = rgb->g; + report.arguments[7] = rgb->b; + report.arguments[8] = rgb->r; + report.arguments[9] = rgb->g; + report.arguments[10] = rgb->b; + report.arguments[11] = rgb->r; + report.arguments[12] = rgb->g; + report.arguments[13] = rgb->b; + + return report; +} + +/** + * Set scroll wheel mode on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 1f 0000 00 02 02 14 0100 | SET SCROLL WHEEL MODE (VARSTR, TACTILE) + * 00 1f 0000 00 02 02 14 0101 | SET SCROLL WHEEL MODE (VARSTR, FREESPIN) + */ +struct razer_report razer_chroma_misc_set_scroll_mode(unsigned int scroll_mode) +{ + struct razer_report report = get_razer_report(0x02, 0x14, 0x02); + + report.arguments[0] = VARSTORE; + report.arguments[1] = scroll_mode; + + return report; +} + +/** + * Get scroll wheel mode from the device + */ +struct razer_report razer_chroma_misc_get_scroll_mode(void) +{ + struct razer_report report = get_razer_report(0x02, 0x94, 0x02); + + report.arguments[0] = VARSTORE; + + return report; +} + +/** + * Set scroll wheel acceleration on/off on the device + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 1f 0000 00 02 02 16 0101 | SET SCROLL WHEEL ACCELERATION (VARSTR, ON) + * 00 1f 0000 00 02 02 16 0100 | SET SCROLL WHEEL ACCELERATION (VARSTR, OFF) + */ +struct razer_report razer_chroma_misc_set_scroll_acceleration(bool acceleration) +{ + struct razer_report report = get_razer_report(0x02, 0x16, 0x02); + + report.arguments[0] = VARSTORE; + report.arguments[1] = acceleration; + + return report; +} + +/** + * Get scroll wheel acceleration state from the device + */ +struct razer_report razer_chroma_misc_get_scroll_acceleration(void) +{ + struct razer_report report = get_razer_report(0x02, 0x96, 0x02); + + report.arguments[0] = VARSTORE; + + return report; +} + +/** + * Set scroll wheel "smart reel" on/off on the device. + * Smart reel automatically changes scroll wheel mode from tactile to free spin and back depending on scroll speed. + * + * Status Trans Packet Proto DataSize Class CMD Args + * 00 1f 0000 00 02 02 17 0101 | SET SCROLL WHEEL SMART REEL (VARSTR, ON) + * 00 1f 0000 00 02 02 17 0100 | SET SCROLL WHEEL SMART REEL (VARSTR, OFF) + */ +struct razer_report razer_chroma_misc_set_scroll_smart_reel(bool smart_reel) +{ + struct razer_report report = get_razer_report(0x02, 0x17, 0x02); + + report.arguments[0] = VARSTORE; + report.arguments[1] = smart_reel; + + return report; +} + +/** + * Get scroll wheel "smart reel" state from the device + */ +struct razer_report razer_chroma_misc_get_scroll_smart_reel(void) +{ + struct razer_report report = get_razer_report(0x02, 0x97, 0x02); + + report.arguments[0] = VARSTORE; + + return report; +} + +/** + * Set LED mode for HyperPolling Wireless Dongle + * 1 = Connection Status + * 2 = Battery Status + * 3 = Battery Warning Only + */ +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_indicator_led_mode(unsigned char mode) +{ + struct razer_report report = get_razer_report(0x07, 0x10, 0x01); + + if(mode < 0x01 || mode > 0x03) { + mode = 0x01; + } + + report.arguments[0] = mode; + + return report; +} + +/** + * Set pairing mode for HyperPolling Wireless Dongle (step 1 of pairing) + */ +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_pair_step1(unsigned short pid) +{ + struct razer_report report; + + report = get_razer_report(0x00, 0x46, 0x01); + report.arguments[0] = 0x01; + + return report; +} + +/** + * Pair HyperPolling Wireless Dongle with PID (step 2 of pairing) + */ +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_pair_step2(unsigned short pid) +{ + struct razer_report report; + + report = get_razer_report(0x00, 0x41, 0x03); + report.arguments[0] = 0x01; + report.arguments[1] = (pid >> 8) & 0xFF; + report.arguments[2] = pid & 0xFF; + + return report; +} + +/** + * Set unpairing mode for HyperPolling Wireless Dongle + */ +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_unpair(unsigned short pid) +{ + struct razer_report report = get_razer_report(0x00, 0x42, 0x02); + + report.arguments[0] = (pid >> 8) & 0xFF; + report.arguments[1] = pid & 0xFF; + + return report; +} diff --git a/openrazer/driver/razerchromacommon.h b/openrazer/driver/razerchromacommon.h new file mode 100644 index 00000000..e17418f9 --- /dev/null +++ b/openrazer/driver/razerchromacommon.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015 Terri Cain + */ + +#ifndef DRIVER_RAZERCHROMACOMMON_H_ +#define DRIVER_RAZERCHROMACOMMON_H_ + +#include "razercommon.h" + +/* + * Standard Device Functions + */ +struct razer_report razer_chroma_standard_set_device_mode(unsigned char mode, unsigned char param); +struct razer_report razer_chroma_standard_get_device_mode(void); + +struct razer_report razer_chroma_standard_get_serial(void); + +struct razer_report razer_chroma_standard_get_firmware_version(void); + +/* + * Standard LED Functions + */ +struct razer_report razer_chroma_standard_set_led_state(unsigned char variable_storage, unsigned char led_id, unsigned char led_state); +struct razer_report razer_chroma_standard_get_led_state(unsigned char variable_storage, unsigned char led_id); + +struct razer_report razer_chroma_standard_set_led_blinking(unsigned char variable_storage, unsigned char led_id); + +struct razer_report razer_chroma_standard_set_led_rgb(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1); +struct razer_report razer_chroma_standard_get_led_rgb(unsigned char variable_storage, unsigned char led_id); + +struct razer_report razer_chroma_standard_set_led_effect(unsigned char variable_storage, unsigned char led_id, unsigned char led_effect); +struct razer_report razer_chroma_standard_get_led_effect(unsigned char variable_storage, unsigned char led_id); + +struct razer_report razer_chroma_standard_set_led_brightness(unsigned char variable_storage, unsigned char led_id, unsigned char brightness); +struct razer_report razer_chroma_standard_get_led_brightness(unsigned char variable_storage, unsigned char led_id); + +/* + * Standard Matrix Effects Functions + */ +struct razer_report razer_chroma_standard_matrix_effect_none(void); +struct razer_report razer_chroma_standard_matrix_effect_wave(unsigned char wave_direction); +struct razer_report razer_chroma_standard_matrix_effect_spectrum(void); +struct razer_report razer_chroma_standard_matrix_effect_reactive(unsigned char speed, struct razer_rgb *rgb1); +struct razer_report razer_chroma_standard_matrix_effect_static(struct razer_rgb *rgb1); +struct razer_report razer_chroma_standard_matrix_effect_starlight_single(unsigned char speed, struct razer_rgb *rgb1); +struct razer_report razer_chroma_standard_matrix_effect_starlight_dual(unsigned char speed, struct razer_rgb *rgb1, struct razer_rgb *rgb2); +struct razer_report razer_chroma_standard_matrix_effect_starlight_random(unsigned char speed); + +struct razer_report razer_chroma_standard_matrix_effect_breathing_random(void); +struct razer_report razer_chroma_standard_matrix_effect_breathing_single(struct razer_rgb *rgb1); +struct razer_report razer_chroma_standard_matrix_effect_breathing_dual(struct razer_rgb *rgb1, struct razer_rgb *rgb2); +struct razer_report razer_chroma_standard_matrix_effect_custom_frame(unsigned char variable_storage); +struct razer_report razer_chroma_standard_matrix_set_custom_frame(unsigned char row_index, unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data); + +/* + * Extended Matrix Effects Functions + * + * Class 0x0F + * Trans 0x3F (Dev 0b001 Game Controller 1, Trans 0b11111) + */ +struct razer_report razer_chroma_extended_matrix_effect_none(unsigned char variable_storage, unsigned char led_id); +struct razer_report razer_chroma_extended_matrix_effect_static(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb); +struct razer_report razer_chroma_extended_matrix_effect_wave(unsigned char variable_storage, unsigned char led_id, unsigned char direction); +struct razer_report razer_chroma_extended_matrix_effect_starlight_random(unsigned char variable_storage, unsigned char led_id, unsigned char speed); +struct razer_report razer_chroma_extended_matrix_effect_starlight_single(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1); +struct razer_report razer_chroma_extended_matrix_effect_starlight_dual(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1, struct razer_rgb *rgb2); +struct razer_report razer_chroma_extended_matrix_effect_spectrum(unsigned char variable_storage, unsigned char led_id); +struct razer_report razer_chroma_extended_matrix_effect_wheel(unsigned char variable_storage, unsigned char led_id, unsigned char direction); +struct razer_report razer_chroma_extended_matrix_effect_reactive(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1); +struct razer_report razer_chroma_extended_matrix_effect_breathing_random(unsigned char variable_storage, unsigned char led_id); +struct razer_report razer_chroma_extended_matrix_effect_breathing_single(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1); +struct razer_report razer_chroma_extended_matrix_effect_breathing_dual(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1, struct razer_rgb *rgb2); +struct razer_report razer_chroma_extended_matrix_effect_custom_frame(void); +struct razer_report razer_chroma_extended_matrix_brightness(unsigned char variable_storage, unsigned char led_id, unsigned char brightness); +struct razer_report razer_chroma_extended_matrix_get_brightness(unsigned char variable_storage, unsigned char led_id); +struct razer_report razer_chroma_extended_matrix_set_custom_frame(unsigned char row_index, unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data); +struct razer_report razer_chroma_extended_matrix_set_custom_frame2(unsigned char row_index, unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data, size_t packetLength); + +/* + * Extended Matrix Effects (Mouse) Functions + * + * Class 0x0D + * Trans 0x3F (not set) (Dev 0b001 Game Controller 1, Trans 0b11111) + */ +struct razer_report razer_chroma_mouse_extended_matrix_effect_none(unsigned char variable_storage, unsigned char led_id); +struct razer_report razer_chroma_mouse_extended_matrix_effect_static(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1); +struct razer_report razer_chroma_mouse_extended_matrix_effect_spectrum(unsigned char variable_storage, unsigned char led_id); +struct razer_report razer_chroma_mouse_extended_matrix_effect_reactive(unsigned char variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1); +struct razer_report razer_chroma_mouse_extended_matrix_effect_breathing_random(unsigned char variable_storage, unsigned char led_id); +struct razer_report razer_chroma_mouse_extended_matrix_effect_breathing_single(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1); +struct razer_report razer_chroma_mouse_extended_matrix_effect_breathing_dual(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1, struct razer_rgb *rgb2); + +/* + * Misc Functions + */ +struct razer_report razer_chroma_misc_fn_key_toggle(unsigned char state); + +struct razer_report razer_chroma_misc_set_keyswitch_optimization_command1(unsigned char optimization_mode); +struct razer_report razer_chroma_misc_set_keyswitch_optimization_command2(unsigned char optimization_mode); +struct razer_report razer_chroma_misc_get_keyswitch_optimization(void); + +struct razer_report razer_chroma_misc_set_blade_brightness(unsigned char brightness); +struct razer_report razer_chroma_misc_get_blade_brightness(void); + +struct razer_report razer_chroma_misc_one_row_set_custom_frame(unsigned char start_col, unsigned char stop_col, unsigned char *rgb_data); +struct razer_report razer_chroma_misc_matrix_reactive_trigger(void); + +struct razer_report razer_chroma_misc_get_battery_level(void); +struct razer_report razer_chroma_misc_get_charging_status(void); + +struct razer_report razer_chroma_misc_set_dock_charge_type(unsigned char charge_type); + +struct razer_report razer_chroma_misc_get_polling_rate(void); +struct razer_report razer_chroma_misc_set_polling_rate(unsigned short polling_rate); + +struct razer_report razer_chroma_misc_get_polling_rate2(void); +struct razer_report razer_chroma_misc_set_polling_rate2(unsigned short polling_rate, unsigned short argument); + +struct razer_report razer_chroma_misc_get_dock_brightness(void); +struct razer_report razer_chroma_misc_set_dock_brightness(unsigned char brightness); + +struct razer_report razer_chroma_misc_set_dpi_xy(unsigned char variable_storage, unsigned short dpi_x,unsigned short dpi_y); +struct razer_report razer_chroma_misc_get_dpi_xy(unsigned char variable_storage); + +struct razer_report razer_chroma_misc_set_dpi_xy_byte(unsigned char dpi_x,unsigned char dpi_y); +struct razer_report razer_chroma_misc_get_dpi_xy_byte(void); + +struct razer_report razer_chroma_misc_set_dpi_stages(unsigned char variable_storage, unsigned char count, unsigned char active_stage, const unsigned short *dpi); +struct razer_report razer_chroma_misc_get_dpi_stages(unsigned char variable_storage); + +struct razer_report razer_chroma_misc_get_idle_time(void); +struct razer_report razer_chroma_misc_set_idle_time(unsigned short idle_time); + +struct razer_report razer_chroma_misc_get_low_battery_threshold(void); +struct razer_report razer_chroma_misc_set_low_battery_threshold(unsigned char battery_threshold); + +struct razer_report razer_chroma_misc_set_orochi2011_led(unsigned char led_bitfield); +struct razer_report razer_chroma_misc_set_orochi2011_poll_dpi(unsigned short poll_rate, unsigned char dpi_x, unsigned char dpi_y); + +struct razer_report razer_naga_trinity_effect_static(struct razer_rgb* rgb); + +struct razer_report razer_chroma_misc_set_scroll_mode(unsigned int scroll_mode); +struct razer_report razer_chroma_misc_get_scroll_mode(void); + +struct razer_report razer_chroma_misc_set_scroll_acceleration(bool acceleration); +struct razer_report razer_chroma_misc_get_scroll_acceleration(void); + +struct razer_report razer_chroma_misc_set_scroll_smart_reel(bool smart_reel); +struct razer_report razer_chroma_misc_get_scroll_smart_reel(void); + +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_indicator_led_mode(unsigned char mode); +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_pair_step1(unsigned short pid); +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_pair_step2(unsigned short pid); +struct razer_report razer_chroma_misc_set_hyperpolling_wireless_dongle_unpair(unsigned short pid); + +#endif diff --git a/openrazer/driver/razercommon.c b/openrazer/driver/razercommon.c new file mode 100644 index 00000000..4e8548ae --- /dev/null +++ b/openrazer/driver/razercommon.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Tim Theede + * 2015 Terri Cain + */ + +#include +#include +#include +#include +#include + +#include "razercommon.h" + +/** + * Send USB control report to the keyboard + * USUALLY index = 0x02 + * FIREFLY is 0 + */ +int razer_send_control_msg(struct usb_device *usb_dev,void const *data, uint report_index, ulong wait_min, ulong wait_max) +{ + uint request = HID_REQ_SET_REPORT; // 0x09 + uint request_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT; // 0x21 + uint value = 0x300; + uint size = RAZER_USB_REPORT_LEN; + char *buf; + int len; + + buf = kmemdup(data, size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + // Send usb control message + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + request, // Request + request_type, // RequestType + value, // Value + report_index, // Index + buf, // Data + size, // Length + USB_CTRL_SET_TIMEOUT); + + // Wait + usleep_range(wait_min, wait_max); + + kfree(buf); + if(len!=size) + printk(KERN_WARNING "razer driver: Device data transfer failed.\n"); + + return ((len < 0) ? len : ((len != size) ? -EIO : 0)); +} + +/** + * Get a response from the razer device + * + * Makes a request like normal, this must change a variable in the device as then we + * tell it give us data and it gives us a report. + * + * Supported Devices: + * Razer Chroma + * Razer Mamba + * Razer BlackWidow Ultimate 2013* + * Razer Firefly* + * + * Request report is the report sent to the device specifying what response we want + * Response report will get populated with a response + * + * Returns 0 when successful, 1 if the report length is invalid. + */ +int razer_get_usb_response(struct usb_device *usb_dev, uint report_index, struct razer_report* request_report, uint response_index, struct razer_report* response_report, ulong wait_min, ulong wait_max) +{ + uint request = HID_REQ_GET_REPORT; // 0x01 + uint request_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN; // 0xA1 + uint value = 0x300; + + uint size = RAZER_USB_REPORT_LEN; // 0x90 + int len; + int retval; + int result = 0; + char *buf; + + if (WARN_ON(request_report->transaction_id.id == 0x00)) { + request_report->transaction_id.id = 0xFF; + } + + buf = kzalloc(sizeof(struct razer_report), GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + // Send the request to the device. + // TODO look to see if index needs to be different for the request and the response + retval = razer_send_control_msg(usb_dev, request_report, report_index, wait_min, wait_max); + + // Now ask for response + len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), + request, // Request + request_type, // RequestType + value, // Value + response_index, // Index + buf, // Data + size, + USB_CTRL_SET_TIMEOUT); + + memcpy(response_report, buf, sizeof(struct razer_report)); + kfree(buf); + + // Error if report is wrong length + if(len != 90) { + printk(KERN_WARNING "razer driver: Invalid USB response. USB Report length: %d\n", len); + result = 1; + } + + if (WARN_ONCE(response_report->data_size > ARRAY_SIZE(response_report->arguments), + "Field data_size %d in response is bigger than arguments\n", + response_report->data_size)) { + /* Sanitize the value since at the moment callers don't respect the return code */ + response_report->data_size = ARRAY_SIZE(response_report->arguments); + return -EINVAL; + } + + return result; +} + +/** + * Calculate the checksum for the usb message + * + * Checksum byte is stored in the 2nd last byte in the messages payload. + * The checksum is generated by XORing all the bytes in the report starting + * at byte number 2 (0 based) and ending at byte 88. + */ +unsigned char razer_calculate_crc(struct razer_report *report) +{ + /*second to last byte of report is a simple checksum*/ + /*just xor all bytes up with overflow and you are done*/ + unsigned char crc = 0; + unsigned char *_report = (unsigned char*)report; + + unsigned int i; + for(i = 2; i < 88; i++) { + crc ^= _report[i]; + } + + return crc; +} + +/** + * Get initialised razer report + */ +struct razer_report get_razer_report(unsigned char command_class, unsigned char command_id, unsigned char data_size) +{ + struct razer_report new_report = {0}; + memset(&new_report, 0, sizeof(struct razer_report)); + + new_report.status = 0x00; + new_report.transaction_id.id = 0x00; + new_report.remaining_packets = 0x00; + new_report.protocol_type = 0x00; + new_report.command_class = command_class; + new_report.command_id.id = command_id; + new_report.data_size = data_size; + + return new_report; +} + +/** + * Get empty razer report + */ +struct razer_report get_empty_razer_report(void) +{ + struct razer_report new_report = {0}; + memset(&new_report, 0, sizeof(struct razer_report)); + + return new_report; +} + +/** + * Print report to syslog + */ +void print_erroneous_report(struct razer_report* report, char* driver_name, char* message) +{ + printk(KERN_WARNING "%s: %s. status: %02x transaction_id.id: %02x remaining_packets: %02x protocol_type: %02x data_size: %02x, command_class: %02x, command_id.id: %02x Params: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x .\n", + driver_name, + message, + report->status, + report->transaction_id.id, + report->remaining_packets, + report->protocol_type, + report->data_size, + report->command_class, + report->command_id.id, + report->arguments[0], report->arguments[1], report->arguments[2], report->arguments[3], report->arguments[4], report->arguments[5], + report->arguments[6], report->arguments[7], report->arguments[8], report->arguments[9], report->arguments[10], report->arguments[11], + report->arguments[12], report->arguments[13], report->arguments[14], report->arguments[15]); +} + +/** + * Clamp a value to a min,max + */ +unsigned char clamp_u8(unsigned char value, unsigned char min, unsigned char max) +{ + if(value > max) + return max; + if(value < min) + return min; + return value; +} +unsigned short clamp_u16(unsigned short value, unsigned short min, unsigned short max) +{ + if(value > max) + return max; + if(value < min) + return min; + return value; +} + +int razer_send_control_msg_old_device(struct usb_device *usb_dev,void const *data, uint report_value, uint report_index, uint report_size, ulong wait_min, ulong wait_max) +{ + uint request = HID_REQ_SET_REPORT; // 0x09 + uint request_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT; // 0x21 + char *buf; + int len; + + buf = kmemdup(data, report_size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + // Send usb control message + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + request, // Request + request_type, // RequestType + report_value, // Value + report_index, // Index + buf, // Data + report_size, // Length + USB_CTRL_SET_TIMEOUT); + + // Wait + usleep_range(wait_min, wait_max); + + kfree(buf); + if(len!=report_size) + printk(KERN_WARNING "razer driver: Device data transfer failed.\n"); + + return ((len < 0) ? len : ((len != report_size) ? -EIO : 0)); +} + +int razer_send_argb_msg(struct usb_device* usb_dev, unsigned char channel, unsigned char size, void const* data) +{ + uint request = HID_REQ_SET_REPORT; // 0x09 + uint request_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT; // 0x21 + uint value = 0x300; + int len; + char *buf; + + struct razer_argb_report report; + + if (channel < 5) { + report.report_id = 0x04; + } else { + report.report_id = 0x84; + } + + report.channel_1 = channel; + report.channel_2 = channel; + + report.pad = 0; + + report.last_idx = size - 1; + + if (size * 3 > ARRAY_SIZE(report.color_data)) { + printk(KERN_ERR "razer driver: size too big\n"); + return -EINVAL; + } + + memcpy(report.color_data, data, size * 3); + + buf = kmemdup(&report, sizeof(report), GFP_KERNEL); + + // Send usb control message + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + request, // Request + request_type, // RequestType + value, // Value + 0x01, // Index + buf, // Data + sizeof(report), // Length + USB_CTRL_SET_TIMEOUT); + + if (len != sizeof(report)) + printk(KERN_WARNING "razer driver: Device data transfer failed. len = %d", len); + + return ((len < 0) ? len : ((len != size) ? -EIO : 0)); +} diff --git a/openrazer/driver/razercommon.h b/openrazer/driver/razercommon.h new file mode 100644 index 00000000..47fbe8f2 --- /dev/null +++ b/openrazer/driver/razercommon.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015 Tim Theede + * 2015 Terri Cain + */ + +#ifndef DRIVER_RAZERCOMMON_H_ +#define DRIVER_RAZERCOMMON_H_ + +#include + +#define DRIVER_VERSION "3.10.3" +#define DRIVER_LICENSE "GPL v2" +#define DRIVER_AUTHOR "Terri Cain " + +// Compatbility for fallthrough pseudo keyword for Linux versions older than v5.4 +// See also https://git.kernel.org/torvalds/c/294f69e +#ifndef fallthrough +#if __has_attribute(__fallthrough__) +# define fallthrough __attribute__((__fallthrough__)) +#else +# define fallthrough do {} while (0) /* fallthrough */ +#endif +#endif + +// Macro to create device files +#define CREATE_DEVICE_FILE(dev, type) \ +do { \ + if(device_create_file(dev, type)) { \ + goto exit_free; \ + } \ +} while (0) + +#define USB_VENDOR_ID_RAZER 0x1532 + +/* Each USB report has 90 bytes*/ +#define RAZER_USB_REPORT_LEN 0x5A + +// LED STATE +#define OFF 0x00 +#define ON 0x01 + +// LED STORAGE Options +#define NOSTORE 0x00 +#define VARSTORE 0x01 + +// LED definitions +#define ZERO_LED 0x00 +#define SCROLL_WHEEL_LED 0x01 +#define BATTERY_LED 0x03 +#define LOGO_LED 0x04 +#define BACKLIGHT_LED 0x05 +#define MACRO_LED 0x07 +#define GAME_LED 0x08 +#define RED_PROFILE_LED 0x0C +#define GREEN_PROFILE_LED 0x0D +#define BLUE_PROFILE_LED 0x0E +#define RIGHT_SIDE_LED 0x10 +#define LEFT_SIDE_LED 0x11 +#define ARGB_CH_1_LED 0x1A +#define ARGB_CH_2_LED 0x1B +#define ARGB_CH_3_LED 0x1C +#define ARGB_CH_4_LED 0x1D +#define ARGB_CH_5_LED 0x1E +#define ARGB_CH_6_LED 0x1F +#define CHARGING_LED 0x20 +#define FAST_CHARGING_LED 0x21 +#define FULLY_CHARGED_LED 0x22 + +// LED Effect definitions +enum razer_classic_effect_id { + CLASSIC_EFFECT_STATIC = 0x00, + CLASSIC_EFFECT_BLINKING = 0x01, + CLASSIC_EFFECT_BREATHING = 0x02, // also called pulsating + CLASSIC_EFFECT_SPECTRUM = 0x04, +}; + +enum razer_matrix_effect_id { + MATRIX_EFFECT_OFF = 0x00, + MATRIX_EFFECT_WAVE = 0x01, + MATRIX_EFFECT_REACTIVE = 0x02, // afterglow + MATRIX_EFFECT_BREATHING = 0x03, + MATRIX_EFFECT_SPECTRUM = 0x04, + MATRIX_EFFECT_CUSTOMFRAME = 0x05, + MATRIX_EFFECT_STATIC = 0x06, + MATRIX_EFFECT_STARLIGHT = 0x19 +}; + +// Report Responses +#define RAZER_CMD_BUSY 0x01 +#define RAZER_CMD_SUCCESSFUL 0x02 +#define RAZER_CMD_FAILURE 0x03 +#define RAZER_CMD_TIMEOUT 0x04 +#define RAZER_CMD_NOT_SUPPORTED 0x05 + +struct razer_report; + +struct razer_rgb { + unsigned char r,g,b; +}; + +union transaction_id_union { + unsigned char id; + struct transaction_parts { + unsigned char device : 3; + unsigned char id : 5; + } parts; +}; + +union command_id_union { + unsigned char id; + struct command_id_parts { + unsigned char direction : 1; + unsigned char id : 7; + } parts; +}; + +/* Status: + * 0x00 New Command + * 0x01 Command Busy + * 0x02 Command Successful + * 0x03 Command Failure + * 0x04 Command No Response / Command Timeout + * 0x05 Command Not Support + * + * Transaction ID used to group request-response, device useful when multiple devices are on one usb + * Remaining Packets is the number of remaining packets in the sequence + * Protocol Type is always 0x00 + * Data Size is the size of payload, cannot be greater than 80. 90 = header (8B) + data + CRC (1B) + Reserved (1B) + * Command Class is the type of command being issued + * Command ID is the type of command being send. Direction 0 is Host->Device, Direction 1 is Device->Host. AKA Get LED 0x80, Set LED 0x00 + * + * */ + +struct razer_report { + unsigned char status; + union transaction_id_union transaction_id; /* */ + unsigned short remaining_packets; /* Big Endian */ + unsigned char protocol_type; /*0x0*/ + unsigned char data_size; + unsigned char command_class; + union command_id_union command_id; + unsigned char arguments[80]; + unsigned char crc;/*xor'ed bytes of report*/ + unsigned char reserved; /*0x0*/ +}; + +struct razer_argb_report { + unsigned char report_id; + unsigned char channel_1; + unsigned char channel_2; + unsigned char pad; + unsigned char last_idx; + unsigned char color_data[315]; +}; + +struct razer_key_translation { + u16 from; + u16 to; +}; + +int razer_send_control_msg(struct usb_device *usb_dev,void const *data, unsigned int report_index, unsigned long wait_min, unsigned long wait_max); +int razer_send_control_msg_old_device(struct usb_device *usb_dev,void const *data, uint report_value, uint report_index, uint report_size, ulong wait_min, ulong wait_max); +int razer_get_usb_response(struct usb_device *usb_dev, unsigned int report_index, struct razer_report* request_report, unsigned int response_index, struct razer_report* response_report, unsigned long wait_min, unsigned long wait_max); +int razer_send_argb_msg(struct usb_device* usb_dev, unsigned char channel, unsigned char size, void const* data); +unsigned char razer_calculate_crc(struct razer_report *report); +struct razer_report get_razer_report(unsigned char command_class, unsigned char command_id, unsigned char data_size); +struct razer_report get_empty_razer_report(void); +void print_erroneous_report(struct razer_report* report, char* driver_name, char* message); + +// Convenience functions +unsigned char clamp_u8(unsigned char value, unsigned char min, unsigned char max); +unsigned short clamp_u16(unsigned short value, unsigned short min, unsigned short max); + +#endif /* DRIVER_RAZERCOMMON_H_ */ diff --git a/openrazer/driver/razerkbd_driver.c b/openrazer/driver/razerkbd_driver.c new file mode 100644 index 00000000..7e1fbb70 --- /dev/null +++ b/openrazer/driver/razerkbd_driver.c @@ -0,0 +1,5874 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Terri Cain + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb_hid_keys.h" + +#include "razerkbd_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/* + * Version Information + */ +#define DRIVER_DESC "Razer Keyboard Device Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE(DRIVER_LICENSE); + +// KEY_MACRO* has been added in Linux 5.5, so define ourselves for older kernels. +// See also https://git.kernel.org/torvalds/c/b5625db +#ifndef KEY_MACRO1 +#define KEY_MACRO1 0x290 +#define KEY_MACRO2 0x291 +#define KEY_MACRO3 0x292 +#define KEY_MACRO4 0x293 +#define KEY_MACRO5 0x294 +#define KEY_MACRO6 0x295 +#define KEY_MACRO7 0x296 +#define KEY_MACRO8 0x297 +#define KEY_MACRO9 0x298 +#define KEY_MACRO10 0x299 +#define KEY_MACRO11 0x2a0 +#define KEY_MACRO12 0x2a1 +// ... +#define KEY_MACRO27 0x2aa +#define KEY_MACRO28 0x2ab +#define KEY_MACRO29 0x2ac +#define KEY_MACRO30 0x2ad +#endif + +// These are evdev key codes, not HID key codes. +// Lower macro key codes are intended for the actual macro keys +// Higher macro key codes are inteded for Chroma functions +#define RAZER_MACRO_KEY KEY_MACRO30 // TODO maybe KEY_MACRO_RECORD_START? +#define RAZER_GAME_KEY KEY_MACRO29 // TODO maybe KEY_GAMES? +#define RAZER_BRIGHTNESS_DOWN KEY_MACRO28 +#define RAZER_BRIGHTNESS_UP KEY_MACRO27 + +/** + * List of keys to swap + */ +static const struct razer_key_translation chroma_keys[] = { + { KEY_F1, KEY_MUTE }, + { KEY_F2, KEY_VOLUMEDOWN }, + { KEY_F3, KEY_VOLUMEUP }, + + { KEY_F5, KEY_PREVIOUSSONG }, + { KEY_F6, KEY_PLAYPAUSE }, + { KEY_F7, KEY_NEXTSONG }, + + { KEY_F9, RAZER_MACRO_KEY }, + { KEY_F10, RAZER_GAME_KEY }, + { KEY_F11, RAZER_BRIGHTNESS_DOWN }, + { KEY_F12, RAZER_BRIGHTNESS_UP }, + + { KEY_PAUSE, KEY_SLEEP }, + + // Custom bind + { KEY_KPENTER, KEY_CALC }, + { 0 } +}; + +static const struct razer_key_translation chroma_keys_2[] = { + { KEY_F1, KEY_MUTE }, + { KEY_F2, KEY_VOLUMEDOWN }, + { KEY_F3, KEY_VOLUMEUP }, + + { KEY_F5, KEY_PLAYPAUSE }, + { KEY_F6, KEY_STOPCD }, + { KEY_F7, KEY_PREVIOUSSONG }, + { KEY_F8, KEY_NEXTSONG }, + { KEY_F11, RAZER_GAME_KEY }, +// { KEY_F12, RAZER_EFFECT_KEY }, // enable if daemon supports, see #577 + { KEY_RIGHTALT, RAZER_MACRO_KEY }, + + { KEY_PAUSE, KEY_SLEEP }, + { 0 } +}; + +// Huntsman Mini Fn keys +static const struct razer_key_translation chroma_keys_3[] = { + { KEY_ESC, KEY_GRAVE }, + { KEY_1, KEY_F1 }, + { KEY_2, KEY_F2 }, + { KEY_3, KEY_F3 }, + { KEY_4, KEY_F4 }, + { KEY_5, KEY_F5 }, + { KEY_6, KEY_F6 }, + { KEY_7, KEY_F7 }, + { KEY_8, KEY_F8 }, + { KEY_9, KEY_F9 }, + { KEY_0, KEY_F10 }, + { KEY_MINUS, KEY_F11 }, + { KEY_EQUAL, KEY_F12 }, + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_TAB, KEY_MUTE }, + { KEY_Q, KEY_VOLUMEDOWN }, + { KEY_W, KEY_VOLUMEUP }, + { KEY_E, KEY_PREVIOUSSONG }, + { KEY_R, KEY_PLAYPAUSE }, + { KEY_T, KEY_NEXTSONG }, + { KEY_Y, RAZER_MACRO_KEY }, + { KEY_U, RAZER_GAME_KEY }, + { KEY_I, KEY_UP }, + { KEY_O, KEY_SCROLLLOCK }, + { KEY_P, KEY_SYSRQ }, + { KEY_LEFTBRACE, KEY_PAGEUP }, + { KEY_RIGHTBRACE, KEY_HOME }, + { KEY_G, RAZER_BRIGHTNESS_DOWN }, + { KEY_H, RAZER_BRIGHTNESS_UP }, + { KEY_J, KEY_LEFT }, + { KEY_K, KEY_DOWN }, + { KEY_L, KEY_RIGHT }, + { KEY_SEMICOLON, KEY_PAGEDOWN }, + { KEY_APOSTROPHE, KEY_END }, + { KEY_Z, KEY_SLEEP }, + { KEY_DOT, KEY_PAUSE }, + { KEY_SLASH, KEY_INSERT }, + { 0 } +}; + +// Blackwidow V3 Mini Fn keys +static const struct razer_key_translation chroma_keys_4[] = { + { KEY_ESC, KEY_GRAVE }, + { KEY_1, KEY_F1 }, + { KEY_2, KEY_F2 }, + { KEY_3, KEY_F3 }, + { KEY_4, KEY_F4 }, + { KEY_5, KEY_F5 }, + { KEY_6, KEY_F6 }, + { KEY_7, KEY_F7 }, + { KEY_8, KEY_F8 }, + { KEY_9, KEY_F9 }, + { KEY_0, KEY_F10 }, + { KEY_MINUS, KEY_F11 }, + { KEY_EQUAL, KEY_F12 }, + { KEY_DELETE, KEY_MACRO1 }, + { KEY_Y, RAZER_MACRO_KEY }, + { KEY_U, RAZER_GAME_KEY }, + { KEY_I, KEY_UP }, + { KEY_O, KEY_SYSRQ }, + { KEY_P, KEY_SCROLLLOCK }, + { KEY_LEFTBRACE, KEY_PAUSE }, + { KEY_RIGHTBRACE, KEY_SLEEP }, + { KEY_PAGEUP, KEY_MACRO2 }, + { KEY_G, RAZER_BRIGHTNESS_DOWN }, + { KEY_H, RAZER_BRIGHTNESS_UP }, + { KEY_APOSTROPHE, KEY_HOME }, + { KEY_PAGEDOWN, KEY_MACRO3 }, + { KEY_V, KEY_MUTE }, + { KEY_B, KEY_VOLUMEDOWN }, + { KEY_N, KEY_VOLUMEUP }, + { KEY_M, KEY_PREVIOUSSONG }, + { KEY_COMMA, KEY_PLAYPAUSE }, + { KEY_DOT, KEY_NEXTSONG }, + { KEY_SLASH, KEY_END }, + { KEY_INSERT, KEY_MACRO4 }, + { KEY_RIGHTALT, KEY_BLUETOOTH }, + { 0 } +}; + +// Razer BlackWidow V3 (Full size) +static const struct razer_key_translation chroma_keys_5[] = { + { KEY_F9, RAZER_MACRO_KEY }, + { KEY_F10, RAZER_GAME_KEY }, + { KEY_F11, RAZER_BRIGHTNESS_DOWN }, + { KEY_F12, RAZER_BRIGHTNESS_UP }, + { KEY_PAUSE, KEY_SLEEP }, + // TODO - Add KEY_CONTEXT_MENU when we figure out what it is supposed to be doing + { 0 } +}; + +// Razer BlackWidow V4 75% +static const struct razer_key_translation chroma_keys_6[] = { + { KEY_F9, RAZER_MACRO_KEY }, + { KEY_F10, RAZER_GAME_KEY }, + { KEY_F11, RAZER_BRIGHTNESS_DOWN }, + { KEY_F12, RAZER_BRIGHTNESS_UP }, + { KEY_P, KEY_SYSRQ }, + { KEY_PAGEUP, KEY_HOME }, + { KEY_PAGEDOWN, KEY_END }, + { KEY_INSERT, KEY_PAUSE }, + { KEY_DELETE, KEY_SLEEP }, + { 0 } +}; + +// Razer DeathStalker V2 Pro TKL +static const struct razer_key_translation chroma_keys_7[] = { + { KEY_F9, RAZER_MACRO_KEY }, + { KEY_F10, RAZER_GAME_KEY }, + { KEY_F11, RAZER_BRIGHTNESS_DOWN }, + { KEY_F12, RAZER_BRIGHTNESS_UP }, + { KEY_INSERT, KEY_SYSRQ }, + { KEY_HOME, KEY_SCROLLLOCK }, + { KEY_PAGEUP, KEY_PAUSE }, + { KEY_PAGEDOWN, KEY_SLEEP }, + // TODO - Add KEY_CONTEXT_MENU when we figure out what it is supposed to be doing + { 0 } +}; + +// Razer Ornata V3 Tenkeyless +static const struct razer_key_translation chroma_keys_8[] = { + { KEY_F9, RAZER_MACRO_KEY }, + { KEY_F10, RAZER_GAME_KEY }, + { KEY_F11, RAZER_BRIGHTNESS_DOWN }, + { KEY_F12, RAZER_BRIGHTNESS_UP }, + { KEY_INSERT, KEY_SYSRQ }, + { KEY_HOME, KEY_SCROLLLOCK }, + { KEY_PAGEUP, KEY_PAUSE }, + { KEY_PAGEDOWN, KEY_SLEEP }, + { KEY_DELETE, KEY_MUTE }, + { 0 } +}; + +/** + * Essentially search through the struct array above. + */ +static const struct razer_key_translation *find_translation(const struct razer_key_translation *key_table, u16 from) +{ + const struct razer_key_translation *result; + + for (result = key_table; result->from; result++) { + if (result->from == from) { + return result; + } + } + + return NULL; +} + +static bool is_blade_laptop(struct razer_kbd_device *device) +{ + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + return true; + } + return false; +} + +/** + * Get request/response indices and timing parameters for the device + */ +static void razer_get_report_params(struct usb_device *usb_dev, uint *report_index, uint *response_index, ulong *wait_min, ulong *wait_max) +{ + switch (usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + *report_index = 0x03; + *response_index = 0x03; + *wait_min = RAZER_BLACKWIDOW_CHROMA_WAIT_MIN_US; + *wait_max = RAZER_BLACKWIDOW_CHROMA_WAIT_MAX_US; + break; + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + *report_index = 0x03; + *response_index = 0x03; + *wait_min = RAZER_BLACKWIDOW_V3_WIRELESS_WAIT_MIN_US; + *wait_max = RAZER_BLACKWIDOW_V3_WIRELESS_WAIT_MAX_US; + break; + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + *report_index = 0x02; + *response_index = 0x02; + *wait_min = RAZER_BLACKWIDOW_CHROMA_WAIT_MIN_US; + *wait_max = RAZER_BLACKWIDOW_CHROMA_WAIT_MAX_US; + break; + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + *report_index = 0x02; + *response_index = 0x02; + *wait_min = RAZER_BLACKWIDOW_V3_WIRELESS_WAIT_MIN_US; + *wait_max = RAZER_BLACKWIDOW_V3_WIRELESS_WAIT_MAX_US; + break; + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + *report_index = 0x02; + *response_index = 0x02; + *wait_min = RAZER_DEATHSTALKER_V2_WIRELESS_WAIT_MIN_US; + *wait_max = RAZER_DEATHSTALKER_V2_WIRELESS_WAIT_MAX_US; + break; + default: + *report_index = 0x01; + *response_index = 0x01; + *wait_min = RAZER_BLACKWIDOW_CHROMA_WAIT_MIN_US; + *wait_max = RAZER_BLACKWIDOW_CHROMA_WAIT_MAX_US; + break; + } +} + +/** + * Send report to the keyboard + */ +static int razer_get_report(struct usb_device *usb_dev, struct razer_report *request, struct razer_report *response) +{ + uint report_index, response_index; + ulong wait_min, wait_max; + razer_get_report_params(usb_dev, &report_index, &response_index, &wait_min, &wait_max); + return razer_get_usb_response(usb_dev, report_index, request, response_index, response, wait_min, wait_max); +} + +/** + * Send report to the keyboard, but without even reading the response + */ +static int razer_send_payload_no_response(struct razer_kbd_device *device, struct razer_report *request) +{ + uint report_index, response_index; + ulong wait_min, wait_max; + + /* Except the caller to have set the transaction_id */ + WARN_ON(request->transaction_id.id == 0x00); + + razer_get_report_params(device->usb_dev, &report_index, &response_index, &wait_min, &wait_max); + return razer_send_control_msg(device->usb_dev, request, report_index, wait_min, wait_max); +} + +/** + * Function to send to device, get response, and actually check the response + */ +static int razer_send_payload(struct razer_kbd_device *device, struct razer_report *request, struct razer_report *response) +{ + int err; + + request->crc = razer_calculate_crc(request); + + mutex_lock(&device->lock); + err = razer_get_report(device->usb_dev, request, response); + mutex_unlock(&device->lock); + if (err) { + print_erroneous_report(response, "razerkbd", "Invalid Report Length"); + return err; + } + + /* Check the packet number, class and command are the same */ + if (response->remaining_packets != request->remaining_packets || + response->command_class != request->command_class || + response->command_id.id != request->command_id.id) { + print_erroneous_report(response, "razerkbd", "Response doesn't match request"); + return -EIO; + } + + switch (response->status) { + case RAZER_CMD_BUSY: + // TODO: Check if this should be an error. + // print_erroneous_report(&response, "razermouse", "Device is busy"); + break; + case RAZER_CMD_FAILURE: + print_erroneous_report(response, "razerkbd", "Command failed"); + return -EIO; + case RAZER_CMD_NOT_SUPPORTED: + print_erroneous_report(response, "razerkbd", "Command not supported"); + return -EIO; + case RAZER_CMD_TIMEOUT: + print_erroneous_report(response, "razerkbd", "Command timed out"); + return -EIO; + } + + return 0; +} + +/** + * Reads the physical layout of the keyboard. + * + * Returns a string + */ +static ssize_t razer_attr_read_kbd_layout(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = get_razer_report(0x00, 0x86, 0x02); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%02x\n", response.arguments[0]); +} + +/** + * Device mode function + */ +static void razer_set_device_mode(struct razer_kbd_device *device, unsigned char mode, unsigned char param) +{ + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (is_blade_laptop(device)) { + return; + } + + request = razer_chroma_standard_set_device_mode(mode, param); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: device_mode not supported for this model\n"); + return; + } + + razer_send_payload(device, &request, &response); +} + +/** + * Read device file "charge_level" + * + * Returns an integer which needs to be scaled from 0-255 -> 0-100 + */ +static ssize_t razer_attr_read_charge_level(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_battery_level(); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request.transaction_id.id = 0x9f; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + request.transaction_id.id = 0x3f; + break; + + default: + printk(KERN_WARNING "razerkbd: charge_level not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[1]); +} + +/** + * Read device file "charge_status" + * + * Returns 0 when not charging, 1 when charging + */ +static ssize_t razer_attr_read_charge_status(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_charging_status(); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request.transaction_id.id = 0x9f; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + request.transaction_id.id = 0x3f; + break; + + default: + printk(KERN_WARNING "razerkbd: charge_status not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[1]); +} + +/** + * Write device file "charge_effect" + * + * Sets charging effect. + */ +static ssize_t razer_attr_write_charge_effect(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 1) { + printk(KERN_WARNING "razerkbd: Incorrect number of bytes for setting the charging effect\n"); + return -EINVAL; + } + + request = razer_chroma_misc_set_dock_charge_type(buf[0]); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "charge_colour" + * + * Sets charging colour using 3 RGB bytes + */ +static ssize_t razer_attr_write_charge_colour(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + // First enable static charging effect + request = razer_chroma_misc_set_dock_charge_type(0x01); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + + if (count != 3) { + printk(KERN_WARNING "razerkbd: Charging colour mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + request = razer_chroma_standard_set_led_rgb(NOSTORE, BATTERY_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "charge_low_threshold" + */ +static ssize_t razer_attr_read_charge_low_threshold(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_low_battery_threshold(); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[0]); +} + +/** + * Write device file "charge_low_threshold" + * + * Sets the low battery blink threshold to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_charge_low_threshold(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char threshold = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_set_low_battery_threshold(threshold); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + return count; +} + +/** + * Write device file "game_led_state" + * + * When 1 is written (as a character, 0x31) Game mode will be enabled, if 0 is written (0x30) + * then game mode will be disabled + * + * The reason the keyboard appears as 2 keyboard devices is that one of those devices is used by + * game mode as that keyboard device is missing a super key. A hacky and over-the-top way to disable + * the super key if you ask me. + */ +static ssize_t razer_attr_write_game_led_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char enabled = (unsigned char)simple_strtoul(buf, NULL, 10); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + request = razer_chroma_standard_set_led_state(NOSTORE, GAME_LED, enabled); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + request = razer_chroma_standard_set_led_state(VARSTORE, GAME_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: game_led_state not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "game_led_state" + * + * Returns a string + */ +static ssize_t razer_attr_read_game_led_state(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + request = razer_chroma_standard_get_led_state(NOSTORE, GAME_LED); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + request = razer_chroma_standard_get_led_state(VARSTORE, GAME_LED); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: game_led_state not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Write device file "keyswitch_optimization" + */ +static ssize_t razer_attr_write_keyswitch_optimization(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char mode = (unsigned char)simple_strtoul(buf, NULL, 10); + + // Toggle Keyswitch Optimization + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + request = razer_chroma_misc_set_keyswitch_optimization_command1(mode); + request.transaction_id.id = 0x1f; + razer_send_payload(device, &request, &response); + request = razer_chroma_misc_set_keyswitch_optimization_command2(mode); + request.transaction_id.id = 0x1f; + razer_send_payload(device, &request, &response); + break; + + default: + printk(KERN_WARNING "razerkbd: keyswitch_optimization not supported for this model\n"); + return -EINVAL; + } + + return count; +} + +/** + * Read device file "keyswitch_optimization" + */ +static ssize_t razer_attr_read_keyswitch_optimization(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + int state; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + request = razer_chroma_misc_get_keyswitch_optimization(); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razerkbd: keyswitch_optimization not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + if(response.arguments[1] == 0x14) { // Either 0x00 or 0x14 + state = 0; // Typing + } else { + state = 1; // Gaming + } + + return sprintf(buf, "%d\n", state); +} + +/** + * Write device file "macro_led_state" + * + * When 1 is written (as a character, 0x31) Macro mode will be enabled, if 0 is written (0x30) + * then game mode will be disabled + */ +static ssize_t razer_attr_write_macro_led_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char enabled = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_set_led_state(VARSTORE, MACRO_LED, enabled); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "macro_led_state" + * + * Returns a string + */ +static ssize_t razer_attr_read_macro_led_state(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_led_state(VARSTORE, MACRO_LED); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "version" + * + * Returns a string + */ +static ssize_t razer_attr_read_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", DRIVER_VERSION); +} + +/** + * Read device file "device_type" + * + * Returns friendly string of device type + */ +static ssize_t razer_attr_read_device_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + char *device_type; + + switch (device->usb_pid) { + + case USB_DEVICE_ID_RAZER_NOSTROMO: + device_type = "Razer Nostromo\n"; + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER: + device_type = "Razer Orbweaver\n"; + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + device_type = "Razer Orbweaver Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + device_type = "Razer BlackWidow Stealth\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + device_type = "Razer BlackWidow Stealth Edition\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + device_type = "Razer BlackWidow Ultimate 2012\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + device_type = "Razer BlackWidow Ultimate 2013\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + device_type = "Razer BlackWidow Ultimate 2016\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + device_type = "Razer BlackWidow X Ultimate\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + device_type = "Razer BlackWidow Tournament Edition 2014\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + device_type = "Razer Blade Stealth\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + device_type = "Razer Blade Stealth (Late 2019)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + device_type = "Razer Blade Stealth (Early 2020)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + device_type = "Razer Blade Stealth (Late 2020)\n"; + break; + + case USB_DEVICE_ID_RAZER_BOOK_2020: + device_type = "Razer Book 13 (2020)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + device_type = "Razer Blade Stealth (Late 2016)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + device_type = "Razer Blade Stealth (Mid 2017)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_QHD: + device_type = "Razer Blade Stealth (QHD)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + device_type = "Razer Blade Pro (Late 2016)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_2018: + device_type = "Razer Blade 15 (2018)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + device_type = "Razer Blade 15 (2018) Mercury\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + device_type = "Razer Blade 15 (2018) Base Model\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + device_type = "Razer Blade 15 (2019) Advanced\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + device_type = "Razer Blade 15 (2019) Base Model\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + device_type = "Razer Blade 15 Base (Early 2020)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + device_type = "Razer Blade 15 Base (Late 2020)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + device_type = "Razer Blade 15 (Mid 2019) Mercury White\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + device_type = "Razer Blade 15 Studio Edition (2019)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + device_type = "Razer Blade (Late 2016)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + device_type = "Razer Blade Pro (2017)\n"; + break; + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + device_type = "Razer Blade Pro FullHD (2017)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + device_type = "Razer Blade Pro (2019)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + device_type = "Razer Blade Pro (Late 2019)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + device_type = "Razer Blade Advanced (Late 2019)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + device_type = "Razer Blade Pro (Early 2020)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + device_type = "Razer Blade Stealth (Late 2017)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + device_type = "Razer Blade Stealth (2019)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + device_type = "Razer Blade 15 Advanced (2020)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + device_type = "Razer Blade 15 Advanced (Early 2021)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + device_type = "Razer Blade 15 Advanced (Mid 2021)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + device_type = "Razer Blade 15 Base (Early 2021)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + device_type = "Razer Blade 15 Base (2022)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + device_type = "Razer Blade 17 Pro (Early 2021)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + device_type = "Razer Blade 17 Pro (Mid 2021)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + device_type = "Razer Blade 14 (2021)\n"; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS: + device_type = "Razer Tartarus\n"; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + device_type = "Razer Tartarus Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + device_type = "Razer Tartarus V2\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + device_type = "Razer BlackWidow Chroma (Overwatch)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + device_type = "Razer BlackWidow Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + device_type = "Razer Deathstalker (Essential)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + device_type = "Razer Deathstalker Expert\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + device_type = "Razer DeathStalker Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + device_type = "Razer BlackWidow Chroma Tournament Edition\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + device_type = "Razer BlackWidow X Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + device_type = "Razer BlackWidow X Chroma Tournament Edition\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + device_type = "Razer BlackWidow Lite\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + device_type = "Razer BlackWidow 2019\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + device_type = "Razer BlackWidow Essential\n"; + break; + + case USB_DEVICE_ID_RAZER_ORNATA: + device_type = "Razer Ornata\n"; + break; + + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + device_type = "Razer Ornata Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V2: + device_type = "Razer Ornata V2\n"; + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + device_type = "Razer Ornata V3\n"; + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + device_type = "Razer Ornata V3 X\n"; + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + device_type = "Razer Ornata V3 Tenkeyless\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + device_type = "Razer Huntsman Elite\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + device_type = "Razer Huntsman Tournament Edition\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + device_type = "Razer BlackWidow Elite\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN: + device_type = "Razer Huntsman\n"; + break; + + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + device_type = "Razer Cynosa Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + device_type = "Razer Cynosa Chroma Pro\n"; + break; + + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + device_type = "Razer Cynosa Lite\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + device_type = "Razer BlackWidow Chroma V2\n"; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + device_type = "Razer Anansi\n"; + break; + + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + device_type = "Razer Cynosa V2\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + device_type = "Razer Huntsman Mini\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + device_type = "Razer Huntsman Mini (JP)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + device_type = "Razer BlackWidow V3\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + device_type = "Razer BlackWidow V3 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + device_type = "Razer BlackWidow V3 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + device_type = "Razer BlackWidow V3 Tenkeyless\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + device_type = "Razer Huntsman V2 Tenkeyless\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + device_type = "Razer Huntsman V2\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + device_type = "Razer Huntsman V2 Analog\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + device_type = "Razer Huntsman Mini Analog\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + device_type = "Razer BlackWidow V3 Mini Hyperspeed (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + device_type = "Razer BlackWidow V3 Mini Hyperspeed (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + device_type = "Razer Blade 17 (2022)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + device_type = "Razer Blade 14 (2022)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + device_type = "Razer Blade 15 Advanced (Early 2022)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + device_type = "Razer Blade 14 (2023)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + device_type = "Razer Blade 14 (2024)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + device_type = "Razer Blade 15 (2023)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + device_type = "Razer DeathStalker V2\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + device_type = "Razer DeathStalker V2 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + device_type = "Razer DeathStalker V2 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + device_type = "Razer BlackWidow V4\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + device_type = "Razer BlackWidow V4 X\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + device_type = "Razer BlackWidow V4 Pro\n"; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + device_type = "Razer BlackWidow V4 75%\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + device_type = "Razer DeathStalker V2 Pro TKL (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + device_type = "Razer DeathStalker V2 Pro TKL (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + device_type = "Razer Blade 16 (2023)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + device_type = "Razer Blade 16 (2025)\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + device_type = "Razer Blade 18 (2023)\n"; + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + device_type = "Razer Huntsman V3 Pro\n"; + break; + + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + device_type = "Razer Blade 18 (2024)\n"; + break; + + default: + device_type = "Unknown Device\n"; + } + + return sprintf(buf, device_type); +} + +/** + * Write device file "macro_led_effect" + * + * When 1 is written the LED will blink, 0 will static + */ +static ssize_t razer_attr_write_macro_led_effect(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char enabled = (unsigned char)simple_strtoul(buf, NULL, 10); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + request = razer_chroma_standard_set_led_effect(NOSTORE, MACRO_LED, enabled); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + request = razer_chroma_standard_set_led_effect(NOSTORE, MACRO_LED, enabled); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + request = razer_chroma_standard_set_led_effect(NOSTORE, MACRO_LED, enabled); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_blinking(NOSTORE, MACRO_LED); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_standard_set_led_effect(VARSTORE, MACRO_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: macro_led_effect not supported for this model\n"); + return -EINVAL; + } + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "macro_led_effect" + * + * Returns a string + */ +static ssize_t razer_attr_read_macro_led_effect(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_led_effect(VARSTORE, MACRO_LED); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Write device file "matrix_effect_pulsate" + * + * The brightness oscillates between fully on and fully off generating a pulsing effect + */ +static ssize_t razer_attr_write_matrix_effect_pulsate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + request = razer_chroma_standard_set_led_effect(VARSTORE, LOGO_LED, CLASSIC_EFFECT_BREATHING); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + request = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, CLASSIC_EFFECT_BREATHING); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_pulsate not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "matrix_effect_pulsate" + * + * Returns a string + */ +static ssize_t razer_attr_read_matrix_effect_pulsate(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_led_effect(VARSTORE, LOGO_LED); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "profile_led_red" + * + * Actually a Yellow LED + * + * Returns a string + */ +static ssize_t razer_attr_read_profile_led_red(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + request = razer_chroma_standard_get_led_state(VARSTORE, BLUE_PROFILE_LED); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_standard_get_led_state(VARSTORE, RED_PROFILE_LED); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: profile_led_red not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "profile_led_green" + * + * Returns a string + */ +static ssize_t razer_attr_read_profile_led_green(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + request = razer_chroma_standard_get_led_state(VARSTORE, RED_PROFILE_LED); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_standard_get_led_state(VARSTORE, GREEN_PROFILE_LED); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: profile_led_green not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "profile_led_blue" + * + * Returns a string + */ +static ssize_t razer_attr_read_profile_led_blue(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + request = razer_chroma_standard_get_led_state(VARSTORE, GREEN_PROFILE_LED); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_standard_get_led_state(VARSTORE, BLUE_PROFILE_LED); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: profile_led_blue not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Write device file "profile_led_red" + */ +static ssize_t razer_attr_write_profile_led_red(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char enabled = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + request = razer_chroma_standard_set_led_state(VARSTORE, BLUE_PROFILE_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_standard_set_led_state(VARSTORE, RED_PROFILE_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: profile_led_red not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "profile_led_green" + */ +static ssize_t razer_attr_write_profile_led_green(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char enabled = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + request = razer_chroma_standard_set_led_state(VARSTORE, RED_PROFILE_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_standard_set_led_state(VARSTORE, GREEN_PROFILE_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: profile_led_green not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + return count; +} + +/** + * Write device file "profile_led_blue" + */ +static ssize_t razer_attr_write_profile_led_blue(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char enabled = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + request = razer_chroma_standard_set_led_state(VARSTORE, GREEN_PROFILE_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_standard_set_led_state(VARSTORE, BLUE_PROFILE_LED, enabled); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: profile_led_blue not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + return count; +} + +/** + * Read device file "device_serial" + * + * Returns a string + */ +static ssize_t razer_attr_read_device_serial(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + char serial_string[51]; + struct razer_report request = {0}; + struct razer_report response = {0}; + + /* For Blade laptops we get the serial number from DMI */ + if (is_blade_laptop(device)) { + strncpy(&serial_string[0], dmi_get_system_info(DMI_PRODUCT_SERIAL), 50); + goto exit; + } + + request = razer_chroma_standard_get_serial(); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + strncpy(&serial_string[0], &response.arguments[0], 22); + serial_string[22] = '\0'; + +exit: + return sprintf(buf, "%s\n", &serial_string[0]); +} + +/** + * Read device file "firmware_version" + * + * Returns a string + */ +static ssize_t razer_attr_read_firmware_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_firmware_version(); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "v%d.%d\n", response.arguments[0], response.arguments[1]); +} + +/** + * Write device file "matrix_effect_none" + * + * No keyboard effect is activated whenever this file is written to + */ +static ssize_t razer_attr_write_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + request = razer_chroma_standard_set_led_state(VARSTORE, BACKLIGHT_LED, OFF); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + request = razer_chroma_standard_matrix_effect_none(); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + request = razer_chroma_standard_matrix_effect_none(); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_none not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_effect_wave" + * + * When 1 is written (as a character, 0x31) the wave effect is displayed moving left across the keyboard + * if 2 is written (0x32) then the wave effect goes right + * + * For the extended its 0x00 and 0x01 + */ +static ssize_t razer_attr_write_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char direction = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + request = razer_chroma_standard_matrix_effect_wave(direction); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + // Direction values are flipped compared to other devices + direction ^= ((1<<0) | (1<<1)); + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + request = razer_chroma_standard_matrix_effect_wave(direction); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_wave not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_effect_wheel" + * + * When 1 is written (as a character, 0x31) the wheel effect is turning right + * if 2 is written (0x32) then the wheel effect goes left. + */ +static ssize_t razer_attr_write_matrix_effect_wheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char direction = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + request = razer_chroma_extended_matrix_effect_wheel(VARSTORE, BACKLIGHT_LED, direction); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_wheel not supported for this model\n"); + return -EINVAL; + } + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_effect_spectrum" + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + request = razer_chroma_standard_set_led_state(VARSTORE, BACKLIGHT_LED, ON); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + request = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, CLASSIC_EFFECT_SPECTRUM); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + request = razer_chroma_standard_matrix_effect_spectrum(); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + request = razer_chroma_standard_matrix_effect_spectrum(); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_spectrum not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_effect_reactive" + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char speed; + + if (count != 4) { + printk(KERN_WARNING "razerkbd: Reactive only accepts Speed, RGB (4byte)\n"); + return -EINVAL; + } + + speed = (unsigned char)buf[0]; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_extended_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + request = razer_chroma_extended_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + request = razer_chroma_standard_matrix_effect_reactive(speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + request = razer_chroma_standard_matrix_effect_reactive(speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_reactive not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_effect_static" + * + * Set the keyboard to static mode when 3 RGB bytes are written + */ +static ssize_t razer_attr_write_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + request = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, CLASSIC_EFFECT_STATIC); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: // Doesn't need any parameters as can only do one type of static + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + request = razer_chroma_standard_set_led_effect(VARSTORE, LOGO_LED, CLASSIC_EFFECT_STATIC); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + if (count != 3) { + printk(KERN_WARNING "razerkbd: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + request = razer_chroma_standard_matrix_effect_static((struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + if (count != 3) { + printk(KERN_WARNING "razerkbd: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + request = razer_chroma_standard_matrix_effect_static((struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + if (count != 3) { + printk(KERN_WARNING "razerkbd: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + request = razer_chroma_extended_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + if (count != 3) { + printk(KERN_WARNING "razerkbd: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + request = razer_chroma_extended_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + if (count != 3) { + printk(KERN_WARNING "razerkbd: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + request = razer_chroma_extended_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x9F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + if (count != 3) { + printk(KERN_WARNING "razerkbd: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + request = razer_chroma_standard_set_led_state(VARSTORE, BACKLIGHT_LED, ON); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + request = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, CLASSIC_EFFECT_STATIC); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + request = razer_chroma_standard_set_led_rgb(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *) &buf[0]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + + default: + printk(KERN_WARNING "razerkbd: Cannot set static mode for this device\n"); + return -EINVAL; + } + + return count; +} + +/** + * Write device file "matrix_effect_starlight" + * + * Starlight keyboard effect is activated whenever this file is written to (for bw2016) + * + * Or if an Ornata + * 7 bytes, speed, rgb, rgb + * 4 bytes, speed, rgb + * 1 byte, speed + */ +static ssize_t razer_attr_write_matrix_effect_starlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_rgb rgb1 = {.r = 0x00, .g = 0xFF, .b = 0x00}; + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORNATA: + if (count != 4) { + printk(KERN_WARNING "razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)\n"); + return -EINVAL; + } + request = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + if(count == 7) { + request = razer_chroma_extended_matrix_effect_starlight_dual(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1], (struct razer_rgb*)&buf[4]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + } else if(count == 4) { + request = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + } else if(count == 1) { + request = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + } else { + printk(KERN_WARNING "razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)\n"); + return -EINVAL; + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + if (count == 7) { + request = razer_chroma_extended_matrix_effect_starlight_dual(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1], (struct razer_rgb*)&buf[4]); + } else if(count == 4) { + request = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1]); + } else if(count == 1) { + request = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + } else { + printk(KERN_WARNING "razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)\n"); + return -EINVAL; + } + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + if (count == 7) { + request = razer_chroma_extended_matrix_effect_starlight_dual(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1], (struct razer_rgb*)&buf[4]); + } else if(count == 4) { + request = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1]); + } else if(count == 1) { + request = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + } else { + printk(KERN_WARNING "razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)\n"); + return -EINVAL; + } + request.transaction_id.id = 0x9F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + if(count == 7) { + request = razer_chroma_extended_matrix_effect_starlight_dual(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1], (struct razer_rgb*)&buf[4]); + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + } else if(count == 4) { + request = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + } else if(count == 1) { + request = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + } else { + printk(KERN_WARNING "razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)\n"); + return -EINVAL; + } + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + if(count == 7) { + request = razer_chroma_standard_matrix_effect_starlight_dual(buf[0], (struct razer_rgb*)&buf[1], (struct razer_rgb*)&buf[4]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + } else if(count == 4) { + request = razer_chroma_standard_matrix_effect_starlight_single(buf[0], (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + } else if(count == 1) { + request = razer_chroma_standard_matrix_effect_starlight_random(buf[0]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + } else { + printk(KERN_WARNING "razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)\n"); + return -EINVAL; + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + if(count == 7) { + request = razer_chroma_standard_matrix_effect_starlight_dual(buf[0], (struct razer_rgb*)&buf[1], (struct razer_rgb*)&buf[4]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + } else if(count == 4) { + request = razer_chroma_standard_matrix_effect_starlight_single(buf[0], (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + } else if(count == 1) { + request = razer_chroma_standard_matrix_effect_starlight_random(buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + } else { + printk(KERN_WARNING "razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)\n"); + return -EINVAL; + } + break; + + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + request = razer_chroma_standard_matrix_effect_starlight_single(0x01, &rgb1); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_starlight not supported for this model\n"); + return -EINVAL; + } + + return count; +} + +/** + * Write device file "matrix_effect_breath" + */ +static ssize_t razer_attr_write_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + default: + printk(KERN_WARNING "razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)\n"); + return -EINVAL; + } + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + request.transaction_id.id = 0x1F; + break; + + case 6: // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + request.transaction_id.id = 0x1F; + break; + + case 1: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + request.transaction_id.id = 0x1F; + break; + + default: + printk(KERN_WARNING "razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)\n"); + return -EINVAL; + } + break; + + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + case 6: // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + case 1: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + default: + printk(KERN_WARNING "razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)\n"); + return -EINVAL; + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + if (count == 3) { // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + } else if (count == 6) { // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + } else if (count == 1) { // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + } else { + printk(KERN_WARNING "razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)\n"); + return -EINVAL; + } + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + if (count == 3) { // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + } else if (count == 6) { // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + } else if (count == 1) { // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + } else { + printk(KERN_WARNING "razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)\n"); + return -EINVAL; + } + request.transaction_id.id = 0x9F; + razer_send_payload(device, &request, &response); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_standard_matrix_effect_breathing_single((struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + case 6: // Dual colour mode + request = razer_chroma_standard_matrix_effect_breathing_dual((struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + + default: // "Random" colour mode + request = razer_chroma_standard_matrix_effect_breathing_random(); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + break; + // TODO move default to case 1:. Then default: printk(warning). Also remove pointless buffer + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_standard_matrix_effect_breathing_single((struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + + case 6: // Dual colour mode + request = razer_chroma_standard_matrix_effect_breathing_dual((struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + + default: // "Random" colour mode + request = razer_chroma_standard_matrix_effect_breathing_random(); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + // TODO move default to case 1:. Then default: printk(warning). Also remove pointless buffer + } + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_breath not supported for this model\n"); + return -EINVAL; + } + + return count; +} + +static int has_inverted_led_state(struct device *dev) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + return 1; + default: + return 0; + } +} + +/** + * Reads device file "logo_led_state" + * + * Reads the logo lighting state (the ASCII number) written to this file. + */ +static ssize_t razer_attr_read_logo_led_state(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + int state; + + request = razer_chroma_standard_get_led_effect(VARSTORE, LOGO_LED); + request.transaction_id.id = 0xFF; + + // Blade laptops don't use effect for logo on/off, and mode 2 ("blink") is technically unsupported. + if (is_blade_laptop(device)) { + request = razer_chroma_standard_get_led_state(VARSTORE, LOGO_LED); + request.transaction_id.id = 0xFF; + } + + razer_send_payload(device, &request, &response); + state = response.arguments[2]; + + if (has_inverted_led_state(dev) && (state == 0 || state == 1)) + state = !state; + + return sprintf(buf, "%d\n", state); +} + +/** + * Write device file "logo_led_state" + * + * Sets the logo lighting state to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_logo_led_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char state = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (has_inverted_led_state(dev) && (state == 0 || state == 1)) + state = !state; + + // Blade laptops are... different. They use state instead of effect. + // Note: This does allow setting of mode 2 ("blink"), but this is an undocumented feature. + if (is_blade_laptop(device) && (state == 0 || state == 1)) { + request = razer_chroma_standard_set_led_state(VARSTORE, LOGO_LED, state); + request.transaction_id.id = 0xFF; + } else { + request = razer_chroma_standard_set_led_effect(VARSTORE, LOGO_LED, state); + request.transaction_id.id = 0xFF; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_effect_custom" + * + * Sets the keyboard to custom mode whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_custom(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + bool want_response = true; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x1F; + want_response = false; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + request = razer_chroma_standard_matrix_effect_custom_frame(NOSTORE); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + request = razer_chroma_standard_matrix_effect_custom_frame(NOSTORE); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_effect_custom not supported for this model\n"); + return -EINVAL; + } + + /* See comment in razer_attr_write_matrix_custom_frame for want_response */ + if (want_response) + razer_send_payload(device, &request, &response); + else + razer_send_payload_no_response(device, &request); + + return count; +} + +/** + * Write device file "fn_toggle" + * + * Sets the logo lighting state to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_fn_toggle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char state = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_fn_key_toggle(state); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "test" + * + * Does nothing + */ +static ssize_t razer_attr_write_test(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +/** + * Read device file "test" + * + * Returns a string + */ +static ssize_t razer_attr_read_test(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = get_razer_report(0x00, 0x86, 0x02); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + print_erroneous_report(&response, "razerkbd", "Test"); + return sprintf(buf, "%02x%02x%02x\n", response.arguments[0], response.arguments[1], response.arguments[2]); +} + +/** + * Write device file "matrix_brightness" + * + * Sets the brightness to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_matrix_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char brightness = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_brightness(VARSTORE, BACKLIGHT_LED, brightness); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_extended_matrix_brightness(VARSTORE, BACKLIGHT_LED, brightness); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request = razer_chroma_extended_matrix_brightness(VARSTORE, BACKLIGHT_LED, brightness); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + request = razer_chroma_standard_set_led_brightness(VARSTORE, LOGO_LED, brightness); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + if (is_blade_laptop(device)) { + request = razer_chroma_misc_set_blade_brightness(brightness); + } else { + request = razer_chroma_standard_set_led_brightness(VARSTORE, BACKLIGHT_LED, brightness); + } + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_brightness not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "matrix_brightness" + * + * Returns a string + */ +static ssize_t razer_attr_read_matrix_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned char brightness = 0; + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + request = razer_chroma_standard_get_led_brightness(VARSTORE, LOGO_LED); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + if (is_blade_laptop(device)) { + request = razer_chroma_misc_get_blade_brightness(); + } else { + request = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + } + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_brightness not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + // Brightness is stored elsewhere for the stealth cmds + if (is_blade_laptop(device)) { + brightness = response.arguments[1]; + } else { + brightness = response.arguments[2]; + } + + return sprintf(buf, "%d\n", brightness); +} + +/** + * Write device file "device_mode" + */ +static ssize_t razer_attr_write_device_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 2) { + printk(KERN_WARNING "razerkbd: Device mode only takes 2 bytes.\n"); + return -EINVAL; + } + + // No-op on Blades + if (is_blade_laptop(device)) { + return count; + } + + request = razer_chroma_standard_set_device_mode(buf[0], buf[1]); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "device_mode" + * + * Returns a string + */ +static ssize_t razer_attr_read_device_mode(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_device_mode(); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + buf[0] = response.arguments[0]; + buf[1] = response.arguments[1]; + + return 2; +} + +/** + * Write device file "matrix_custom_frame" + * + * Format + * ROW_ID START_COL STOP_COL RGB... + */ +static ssize_t razer_attr_write_matrix_custom_frame(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + size_t offset = 0; + unsigned char row_id, start_col, stop_col; + size_t row_length; + bool want_response = true; + + while(offset < count) { + if(offset + 3 > count) { + printk(KERN_ALERT "razerkbd: Wrong Amount of data provided: Should be ROW_ID, START_COL, STOP_COL, N_RGB\n"); + return -EINVAL; + } + + row_id = buf[offset++]; + start_col = buf[offset++]; + stop_col = buf[offset++]; + + // Validate parameters + if(start_col > stop_col) { + printk(KERN_ALERT "razerkbd: Start column (%u) is greater than end column (%u)\n", start_col, stop_col); + return -EINVAL; + } + + row_length = ((stop_col + 1) - start_col) * 3; + + // Make sure we actually got the data that was promised to us + if(count < offset + row_length) { + printk(KERN_ALERT "razerkbd: Not enough RGB to fill row (expecting %lu bytes of RGB data, got %lu)\n", row_length, (count - 3)); + return -EINVAL; + } + + // printk(KERN_INFO "razerkbd: Row ID: %u, Start: %u, Stop: %u, row length: %lu\n", row_id, start_col, stop_col, row_length); + + // Offset now at beginning of RGB data + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x1F; + want_response = false; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x9F; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + request = razer_chroma_misc_one_row_set_custom_frame(start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + request = razer_chroma_standard_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + request = razer_chroma_standard_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razerkbd: matrix_custom_frame not supported for this model\n"); + return -EINVAL; + } + + /* + * Some devices don't like us asking for responses for custom frame + * requests. And in any case it shouldn't be necessary for most devices + * but let's keep it enabled by default for now to not potentially + * break anything. + */ + if (want_response) + razer_send_payload(device, &request, &response); + else + razer_send_payload_no_response(device, &request); + + // *3 as its 3 bytes per col (RGB) + offset += row_length; + } + + return count; +} + +/** + * Read device file "poll_rate" + * + * Returns a string + */ +static ssize_t razer_attr_read_poll_rate(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned short polling_rate = 0; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + request = razer_chroma_misc_get_polling_rate2(); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razerkbd: poll_rate not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + switch(response.arguments[1]) { + case 0x01: + polling_rate = 8000; + break; + case 0x02: + polling_rate = 4000; + break; + case 0x04: + polling_rate = 2000; + break; + case 0x08: + polling_rate = 1000; + break; + case 0x10: + polling_rate = 500; + break; + case 0x20: + polling_rate = 250; + break; + case 0x40: + polling_rate = 125; + break; + } + + return sprintf(buf, "%d\n", polling_rate); +} + +/** + * Write device file "poll_rate" + * + * Sets the poll rate + */ +static ssize_t razer_attr_write_poll_rate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + unsigned short polling_rate = (unsigned short)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + request = razer_chroma_misc_set_polling_rate2(polling_rate, 0x00); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razerkbd: poll_rate not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "key_super" + */ +static ssize_t razer_attr_write_key_super(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + if (count < 1) { + printk(KERN_ALERT "razerkbd: Failed to provide argument\n"); + return -EINVAL; + } + + device->block_keys[0] = buf[0]; + + return count; +} + +/** + * Read device file "key_super" + */ +static ssize_t razer_attr_read_key_super(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + buf[0] = device->block_keys[0]; + + return 1; +} + +/** + * Write device file "key_alt_tab" + */ +static ssize_t razer_attr_write_key_alt_tab(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + if (count < 1) { + printk(KERN_ALERT "razerkbd: Failed to provide argument\n"); + return -EINVAL; + } + + printk(KERN_WARNING "razerkbd: Settings block_keys[1] to %u\n", buf[0]); + device->block_keys[1] = buf[0]; + + return count; +} + +/** + * Read device file "read_key_alt_tab" + */ +static ssize_t razer_attr_read_key_alt_tab(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + buf[0] = device->block_keys[1]; + + return 1; +} + +/** + * Write device file "write_key_alt_f4" + */ +static ssize_t razer_attr_write_key_alt_f4(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + if (count < 1) { + printk(KERN_ALERT "razerkbd: Failed to provide argument\n"); + return -EINVAL; + } + + device->block_keys[2] = buf[0]; + + return count; +} + +/** + * Read device file "read_key_alt_f4" + */ +static ssize_t razer_attr_read_key_alt_f4(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kbd_device *device = dev_get_drvdata(dev); + + buf[0] = device->block_keys[2]; + + return 1; +} + +/** + * Set up the device driver files + + * + * Read only is 0444 + * Write only is 0220 + * Read and write is 0664 + */ +static DEVICE_ATTR(game_led_state, 0660, razer_attr_read_game_led_state, razer_attr_write_game_led_state); +static DEVICE_ATTR(macro_led_state, 0660, razer_attr_read_macro_led_state, razer_attr_write_macro_led_state); +static DEVICE_ATTR(macro_led_effect, 0660, razer_attr_read_macro_led_effect, razer_attr_write_macro_led_effect); +static DEVICE_ATTR(logo_led_state, 0660, razer_attr_read_logo_led_state, razer_attr_write_logo_led_state); +static DEVICE_ATTR(profile_led_red, 0660, razer_attr_read_profile_led_red, razer_attr_write_profile_led_red); +static DEVICE_ATTR(profile_led_green, 0660, razer_attr_read_profile_led_green, razer_attr_write_profile_led_green); +static DEVICE_ATTR(profile_led_blue, 0660, razer_attr_read_profile_led_blue, razer_attr_write_profile_led_blue); + +static DEVICE_ATTR(test, 0660, razer_attr_read_test, razer_attr_write_test); +static DEVICE_ATTR(version, 0440, razer_attr_read_version, NULL); +static DEVICE_ATTR(kbd_layout, 0440, razer_attr_read_kbd_layout, NULL); + +static DEVICE_ATTR(firmware_version, 0440, razer_attr_read_firmware_version, NULL); +static DEVICE_ATTR(fn_toggle, 0220, NULL, razer_attr_write_fn_toggle); +static DEVICE_ATTR(poll_rate, 0660, razer_attr_read_poll_rate, razer_attr_write_poll_rate); +static DEVICE_ATTR(keyswitch_optimization, 0660, razer_attr_read_keyswitch_optimization, razer_attr_write_keyswitch_optimization); + +static DEVICE_ATTR(device_type, 0440, razer_attr_read_device_type, NULL); +static DEVICE_ATTR(device_mode, 0660, razer_attr_read_device_mode, razer_attr_write_device_mode); +static DEVICE_ATTR(device_serial, 0440, razer_attr_read_device_serial, NULL); + +static DEVICE_ATTR(matrix_effect_none, 0220, NULL, razer_attr_write_matrix_effect_none); +static DEVICE_ATTR(matrix_effect_wave, 0220, NULL, razer_attr_write_matrix_effect_wave); +static DEVICE_ATTR(matrix_effect_wheel, 0220, NULL, razer_attr_write_matrix_effect_wheel); +static DEVICE_ATTR(matrix_effect_spectrum, 0220, NULL, razer_attr_write_matrix_effect_spectrum); +static DEVICE_ATTR(matrix_effect_reactive, 0220, NULL, razer_attr_write_matrix_effect_reactive); +static DEVICE_ATTR(matrix_effect_static, 0220, NULL, razer_attr_write_matrix_effect_static); +static DEVICE_ATTR(matrix_effect_starlight, 0220, NULL, razer_attr_write_matrix_effect_starlight); +static DEVICE_ATTR(matrix_effect_breath, 0220, NULL, razer_attr_write_matrix_effect_breath); +static DEVICE_ATTR(matrix_effect_pulsate, 0660, razer_attr_read_matrix_effect_pulsate, razer_attr_write_matrix_effect_pulsate); +static DEVICE_ATTR(matrix_brightness, 0660, razer_attr_read_matrix_brightness, razer_attr_write_matrix_brightness); +static DEVICE_ATTR(matrix_effect_custom, 0220, NULL, razer_attr_write_matrix_effect_custom); +static DEVICE_ATTR(matrix_custom_frame, 0220, NULL, razer_attr_write_matrix_custom_frame); + +static DEVICE_ATTR(key_super, 0660, razer_attr_read_key_super, razer_attr_write_key_super); +static DEVICE_ATTR(key_alt_tab, 0660, razer_attr_read_key_alt_tab, razer_attr_write_key_alt_tab); +static DEVICE_ATTR(key_alt_f4, 0660, razer_attr_read_key_alt_f4, razer_attr_write_key_alt_f4); + +static DEVICE_ATTR(charge_level, 0440, razer_attr_read_charge_level, NULL); +static DEVICE_ATTR(charge_status, 0440, razer_attr_read_charge_status, NULL); +static DEVICE_ATTR(charge_effect, 0220, NULL, razer_attr_write_charge_effect); +static DEVICE_ATTR(charge_colour, 0220, NULL, razer_attr_write_charge_colour); +static DEVICE_ATTR(charge_low_threshold, 0660, razer_attr_read_charge_low_threshold, razer_attr_write_charge_low_threshold); + +/** + * Deal with FN toggle + */ +static int razer_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) +{ + struct razer_kbd_device *device = hid_get_drvdata(hdev); + const struct razer_key_translation *translation; + + // No translations needed on the Blades + if (is_blade_laptop(device)) { + return 0; + } + + if(device->usb_interface_protocol == USB_INTERFACE_PROTOCOL_MOUSE) { + // Skip this if its control (mouse) interface + return 0; + } + + // Block win key + if(device->block_keys[0] && (usage->code == KEY_LEFTMETA || usage->code == KEY_RIGHTMETA)) { + return 1; + } + + // Store Alt state + if(usage->code == KEY_LEFTALT) { + device->left_alt_on = value; + } + // Block Alt-Tab + if(device->block_keys[1] && device->left_alt_on && usage->code == KEY_TAB) { + return 1; + } + // Block Alt-F4 + if(device->block_keys[2] && device->left_alt_on && usage->code == KEY_F4) { + return 1; + } + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + translation = find_translation(chroma_keys_2, usage->code); + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + translation = find_translation(chroma_keys_3, usage->code); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + translation = find_translation(chroma_keys_4, usage->code); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + translation = find_translation(chroma_keys_5, usage->code); + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + translation = find_translation(chroma_keys_7, usage->code); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + translation = find_translation(chroma_keys_6, usage->code); + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + translation = find_translation(chroma_keys_8, usage->code); + break; + + default: + translation = find_translation(chroma_keys, usage->code); + break; + } + + if(translation) { + if (test_bit(usage->code, device->pressed_fn) || device->fn_on) { + if (value) { + set_bit(usage->code, device->pressed_fn); + } else { + clear_bit(usage->code, device->pressed_fn); + } + + input_event(field->hidinput->input, usage->type, translation->to, value); + return 1; + } + } + + return 0; +} + +/** + * Standard raw event function + * + * Bastard function. Could most probably be done a load better. + * Basically it shifts all of the key's in the 04... event to the right 1, and then sets the first 2 bytes to 0x0100. This then allows the keys to be processed with the above normal event function + * + * Converts M1-M5 into F13-F17. It also blanks out FN keypresses so it acts more like the modifier it should be. + * 04012000000000000000 FN is pressed, M1 pressed + * 04010000000000000000 M1 is released + * goes to + * 01000068000000000000 FN is pressed (blanked), M1 pressed (converted to F13) + * 01000000000000000000 M1 is released + * + * Converts Mute/Next/Play/Prev into multimedia keys + * 04 00 52 00 ... 00 - Mute key pressed + * 04 00 00 00 ... 00 - Mute key released + * goes to + * 01 00 00 E2 00 ... 00 - Mute pressed (converted to KEY_MEDIA_MUTE) + * 01 00 00 00 00 ... 00 + * they key codes are + * 0x52 - Mute + * 0x53 - Next song + * 0x55 - Play/Pause + * 0x54 - Prev song + * + * HID Usage Table http://www.freebsddiary.org/APC/usb_hid_usages.php + */ +static int razer_raw_event_standard(struct hid_device *hdev, struct razer_kbd_device *device, struct usb_interface *intf, struct hid_report *report, u8 *data, int size) +{ + // The event were looking for is 16, 22 or 48 bytes long and starts with 0x04. + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD && + ((size == 48) || (size == 22) || (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) + int found_fn = 0x00; + + while(--index > 0) { + u8 cur_value = data[index]; + if(cur_value == 0x00) { // Skip 0x00 + continue; + } + + switch(cur_value) { + case 0x01: // FN + //cur_value = 0x73; // F24 + cur_value = 0x00; + found_fn = 0x01; + break; + case 0x20: // M1 + cur_value = USB_HID_KEY_F13; // F13 + break; + case 0x21: // M2 + cur_value = USB_HID_KEY_F14; // F14 + break; + case 0x22: // M3 + cur_value = USB_HID_KEY_F15; // F15 + break; + case 0x23: // M4 + cur_value = USB_HID_KEY_F16; // F16 + break; + case 0x24: // M5 + cur_value = USB_HID_KEY_F17; // F17 + break; + case 0x25: // BlackWidow V4 (non-Pro) M6 + cur_value = USB_HID_KEY_F18; // F18 + break; + case 0x50: // Volume Down + cur_value = USB_HID_KEY_MEDIA_VOLUMEDOWN; // F17 + break; + case 0x51: // Volume Up + cur_value = USB_HID_KEY_MEDIA_VOLUMEUP; // F17 + break; + case 0x52: // Mute + cur_value = USB_HID_KEY_MEDIA_MUTE; + break; + case 0x53: // Next (song) + cur_value = USB_HID_KEY_MEDIA_NEXTSONG; + break; + case 0x55: // Play/Pause + cur_value = USB_HID_KEY_MEDIA_PLAYPAUSE; + break; + case 0x54: // Prev (song) + cur_value = USB_HID_KEY_MEDIA_PREVIOUSSONG; + break; + case 0x60: // BlackWidow V4 Pro command dial button + cur_value = USB_HID_KEY_F24; // F24 (not sure if we want it this way) + break; + case 0x63: // BlackWidow V4 Pro Side button 1 + cur_value = USB_HID_KEY_F18; // F18 + break; + case 0x64: // BlackWidow V4 Pro Side button 2 + cur_value = USB_HID_KEY_F19; // F19 + break; + case 0x65: // BlackWidow V4 Pro Side button 3 + cur_value = USB_HID_KEY_F20; // F20 + break; + } + + data[index+1] = cur_value; + } + + device->fn_on = !!found_fn; + + data[0] = 0x01; + data[1] = 0x00; + + // Some reason just by editing data, it generates a normal event above. (Could quite possibly work like that, no clue) + //hid_report_raw_event(hdev, HID_INPUT_REPORT, data, size, 0); + return 1; + } + + return 0; +} + +#define RAW_EVENT_BITFIELD_BYTES (20) +#define RAW_EVENT_BITFIELD_BITS (RAW_EVENT_BITFIELD_BYTES * BITS_PER_BYTE) + +/** + * Bitfield raw event function + * + * Handles raw events very similarly to razer_raw_event_standard, but for size 22, handles the data as a bit field, + * instead of an array of values. + * + * When the rewritten value does not fit the bit field, a key-down and a key-up event is reported separately. + */ +static int razer_raw_event_bitfield(struct hid_device *hdev, struct razer_kbd_device *device, struct usb_interface *intf, struct hid_report *report, u8 *data, int size) +{ + DECLARE_BITMAP(bitfield, RAW_EVENT_BITFIELD_BITS) = { 0 }; + + // The event were looking for is 16, 22 or 48 bytes long and starts with 0x04. + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD && + ((size == 48) || (size == 22) || (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) + int found_fn = 0x00; + + while(--index > 0) { + bool write_bitfield = true; + u8 cur_value = data[index]; + if(cur_value == 0x00) { // Skip 0x00 + continue; + } + + switch(cur_value) { + case 0x01: // FN + //cur_value = 0x73; // F24 + cur_value = 0x00; + found_fn = 0x01; + write_bitfield = false; + break; + case 0x20: // M1 + cur_value = USB_HID_KEY_F13; // F13 + break; + case 0x21: // M2 + cur_value = USB_HID_KEY_F14; // F14 + break; + case 0x22: // M3 + cur_value = USB_HID_KEY_F15; // F15 + break; + case 0x23: // M4 + cur_value = USB_HID_KEY_F16; // F16 + break; + case 0x24: // M5 + cur_value = USB_HID_KEY_F17; // F17 + break; + case 0x25: // BlackWidow V4 (non-Pro) M6 + cur_value = USB_HID_KEY_F18; // F18 + break; + case 0x50: // Volume Down + cur_value = USB_HID_KEY_MEDIA_VOLUMEDOWN; + break; + case 0x51: // Volume Up + cur_value = USB_HID_KEY_MEDIA_VOLUMEUP; + break; + case 0x52: // Mute + cur_value = USB_HID_KEY_MEDIA_MUTE; + break; + case 0x53: // Next (song) + cur_value = USB_HID_KEY_MEDIA_NEXTSONG; + break; + case 0x55: // Play/Pause + cur_value = USB_HID_KEY_MEDIA_PLAYPAUSE; + break; + case 0x54: // Prev (song) + cur_value = USB_HID_KEY_MEDIA_PREVIOUSSONG; + break; + case 0x60: // BlackWidow V4 Pro command dial button + cur_value = USB_HID_KEY_F24; // F24 (not sure if we want it this way) + break; + case 0x63: // BlackWidow V4 Pro Side button 1 + cur_value = USB_HID_KEY_F18; // F18 + break; + case 0x64: // BlackWidow V4 Pro Side button 2 + cur_value = USB_HID_KEY_F19; // F19 + break; + case 0x65: // BlackWidow V4 Pro Side button 3 + cur_value = USB_HID_KEY_F20; // F20 + break; + default: + write_bitfield = false; + } + + // data of size 22 starting with 0x01 is a bit field so we need to handle that separately + if (size == 22) { + if (write_bitfield) { + if (cur_value < RAW_EVENT_BITFIELD_BITS) { + // value fits the bit field, so we can use that + bitmap_set(bitfield, cur_value, 1); + } else { + // value does not fit the bit field, so we need extra handling + int report_extra = 1; + + switch (cur_value) { + case USB_HID_KEY_MEDIA_VOLUMEUP: + cur_value = USB_HID_USAGE_MEDIA_VOLUMEUP; + break; + case USB_HID_KEY_MEDIA_VOLUMEDOWN: + cur_value = USB_HID_USAGE_MEDIA_VOLUMEDOWN; + break; + case USB_HID_KEY_MEDIA_MUTE: + cur_value = USB_HID_USAGE_MEDIA_MUTE; + break; + case USB_HID_KEY_MEDIA_NEXTSONG: + cur_value = USB_HID_USAGE_MEDIA_NEXTSONG; + break; + case USB_HID_KEY_MEDIA_PLAYPAUSE: + cur_value = USB_HID_USAGE_MEDIA_PLAYPAUSE; + break; + case USB_HID_KEY_MEDIA_PREVIOUSSONG: + cur_value = USB_HID_USAGE_MEDIA_PREVIOUSSONG; + break; + default: + report_extra = 0; + } + + if (report_extra) { + u8 xdata[22] = { 0x02 }; + + // report key down + xdata[1] = cur_value; + hid_report_raw_event(hdev, HID_INPUT_REPORT, xdata, sizeof(xdata), 0); + + // report key up + xdata[1] = 0x00; + hid_report_raw_event(hdev, HID_INPUT_REPORT, xdata, sizeof(xdata), 0); + } + } + } + } else { // size 16 + data[index+1] = cur_value; + } + } + + device->fn_on = !!found_fn; + + data[0] = 0x01; + data[1] = 0x00; + if (size == 22) { + memcpy(data + 2, bitfield, RAW_EVENT_BITFIELD_BYTES); + } + + // Some reason just by editing data, it generates a normal event above. (Could quite possibly work like that, no clue) + //hid_report_raw_event(hdev, HID_INPUT_REPORT, data, size, 0); + return 1; + } + + return 0; +} + +/** + * Raw event function + * + * Handles provided HID reports, branched out for specific keyboard models, since some keyboards need specific handling. + */ +static int razer_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) +{ + struct razer_kbd_device *device = hid_get_drvdata(hdev); + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + + // No translations needed on the Pro... + if (is_blade_laptop(device)) { + return 0; + } + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + return razer_raw_event_bitfield(hdev, device, intf, report, data, size); + default: + return razer_raw_event_standard(hdev, device, intf, report, data, size); + } +} + +/** + * Set static hid-events translation map + * + * Some keyboards generates wheel-events for volume control knob + */ +static int razer_kbd_input_mapping(struct hid_device *hdev, struct hid_input *hidinput, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, int *max) +{ + switch (hdev->product) { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + if (hdev->type == HID_TYPE_USBMOUSE && usage->hid == HID_GD_WHEEL) { + hid_map_usage(hidinput, usage, bit, max, EV_ABS, ABS_VOLUME); + return 1; + } + return 0; + + default: + return 0; + } +} + +static void razer_kbd_init(struct razer_kbd_device *dev, struct usb_interface *intf, struct hid_device *hdev) +{ + struct usb_device *usb_dev = interface_to_usbdev(intf); + + // Initialise mutex + mutex_init(&dev->lock); + // Setup values + dev->usb_dev = usb_dev; + dev->usb_vid = usb_dev->descriptor.idVendor; + dev->usb_pid = usb_dev->descriptor.idProduct; + dev->usb_interface_protocol = intf->cur_altsetting->desc.bInterfaceProtocol; +} + +/** + * Probe method is ran whenever a device is binded to the driver + */ +static int razer_kbd_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int retval = 0; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct razer_kbd_device *dev = NULL; + + dev = kzalloc(sizeof(struct razer_kbd_device), GFP_KERNEL); + if(dev == NULL) { + dev_err(&intf->dev, "out of memory\n"); + return -ENOMEM; + } + + // Init data + razer_kbd_init(dev, intf, hdev); + + // Other interfaces are actual key-emitting devices + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { + // If the currently bound device is the control (mouse) interface + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_version); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_firmware_version); // Get the firmware version + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_serial); // Get serial number + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); // Gets and sets the brightness + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_test); // Test mode + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_type); // Get string of device type + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_mode); // Get device mode + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_kbd_layout); // Gets the physical layout + + switch(usb_dev->descriptor.idProduct) { + + case USB_DEVICE_ID_RAZER_NOSTROMO: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + break; + + case USB_DEVICE_ID_RAZER_TARTARUS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_pulsate); // Pulsate effect, like breathing + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_pulsate); // Pulsate effect, like breathing + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_pulsate); // Pulsate effect, like breathing + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_ORNATA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_super); // Super Key + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_alt_tab); // Alt + Tab + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_alt_f4); // Alt + F4 + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); // Charge level + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); // Charge status + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); // Poll Rate + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_keyswitch_optimization); // Keyswitch Optimization + fallthrough; + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_super); // Super Key + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_alt_tab); // Alt + Tab + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_alt_f4); // Alt + F4 + fallthrough; + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wheel); // Wheel effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wheel); // Wheel effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); // Poll Rate + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); // Battery charge level + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); // Battery charge status + break; + + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); // Charge level + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); // Charge status + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); // Charge effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); // Charge colour + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); // Charge low threshold + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + break; + + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + break; + + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fn_toggle); // Sets whether FN is requires for F-Keys + break; + + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_fn_toggle); // Sets whether FN is requires for F-Keys + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_state); // Enable/Disable the logo + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_state); // Enable/Disable the logo + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + } + + // Set device to regular mode, not driver mode + // When the daemon discovers the device it will instruct it to enter driver mode + razer_set_device_mode(dev, 0x00, 0x00); + } else if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD) { + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_super); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_alt_tab); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_key_alt_f4); + } + + hid_set_drvdata(hdev, dev); + dev_set_drvdata(&hdev->dev, dev); + + if(hid_parse(hdev)) { + hid_err(hdev, "parse failed\n"); + goto exit_free; + } + + if (hid_hw_start(hdev, HID_CONNECT_DEFAULT)) { + hid_err(hdev, "hw start failed\n"); + goto exit_free; + } + + // Leave autosuspend on for laptops + if (!is_blade_laptop(dev)) { + usb_disable_autosuspend(usb_dev); + } + + //razer_activate_macro_keys(usb_dev); + //msleep(3000); + return 0; + +exit_free: + kfree(dev); + return retval; +} + +/** + * Unbind function + */ +static void razer_kbd_disconnect(struct hid_device *hdev) +{ + struct razer_kbd_device *dev; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + + dev = hid_get_drvdata(hdev); + + // Other interfaces are actual key-emitting devices + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { + // If the currently bound device is the control (mouse) interface + device_remove_file(&hdev->dev, &dev_attr_version); + device_remove_file(&hdev->dev, &dev_attr_firmware_version); // Get the firmware version + device_remove_file(&hdev->dev, &dev_attr_device_serial); // Get serial number + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); // Gets and sets the brightness + device_remove_file(&hdev->dev, &dev_attr_test); // Test mode + device_remove_file(&hdev->dev, &dev_attr_device_type); // Get string of device type + device_remove_file(&hdev->dev, &dev_attr_device_mode); // Get device mode + device_remove_file(&hdev->dev, &dev_attr_kbd_layout); // Gets the physical layout + + switch(usb_dev->descriptor.idProduct) { + + case USB_DEVICE_ID_RAZER_NOSTROMO: + device_remove_file(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + device_remove_file(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + device_remove_file(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + break; + + case USB_DEVICE_ID_RAZER_TARTARUS: + device_remove_file(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + device_remove_file(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + device_remove_file(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_pulsate); // Pulsate effect, like breathing + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER: + device_remove_file(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + device_remove_file(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + device_remove_file(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_pulsate); // Pulsate effect, like breathing + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + device_remove_file(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + device_remove_file(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + device_remove_file(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + device_remove_file(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_game_led_state); + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_pulsate); // Pulsate effect, like breathing + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLADE_2018_BASE: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020: + case USB_DEVICE_ID_RAZER_BOOK_2020: + case USB_DEVICE_ID_RAZER_BLADE_2019_BASE: + case USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_ORNATA: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_key_super); // Super Key + device_remove_file(&hdev->dev, &dev_attr_key_alt_tab); // Alt + Tab + device_remove_file(&hdev->dev, &dev_attr_key_alt_f4); // Alt + F4 + device_remove_file(&hdev->dev, &dev_attr_charge_level); // Charge level + device_remove_file(&hdev->dev, &dev_attr_charge_status); // Charge status + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); // Poll Rate + device_remove_file(&hdev->dev, &dev_attr_keyswitch_optimization); // Keyswitch Optimization + fallthrough; + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_V2: + device_remove_file(&hdev->dev, &dev_attr_key_super); // Super Key + device_remove_file(&hdev->dev, &dev_attr_key_alt_tab); // Alt + Tab + device_remove_file(&hdev->dev, &dev_attr_key_alt_f4); // Alt + F4 + fallthrough; + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_ORNATA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3: + case USB_DEVICE_ID_RAZER_ORNATA_V3_ALT: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wheel); // Wheel effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wheel); // Wheel + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + device_remove_file(&hdev->dev, &dev_attr_poll_rate); // Poll Rate + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + device_remove_file(&hdev->dev, &dev_attr_charge_level); // Battery charge level + device_remove_file(&hdev->dev, &dev_attr_charge_status); // Battery charge status + break; + + case USB_DEVICE_ID_RAZER_CYNOSA_LITE: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_ORNATA_V3_X: + case USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + device_remove_file(&hdev->dev, &dev_attr_charge_level); // Charge level + device_remove_file(&hdev->dev, &dev_attr_charge_status); // Charge status + device_remove_file(&hdev->dev, &dev_attr_charge_effect); // Charge effect + device_remove_file(&hdev->dev, &dev_attr_charge_colour); // Charge colour + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); // Charge low threshold + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_profile_led_red); // Profile/Macro LED Red + device_remove_file(&hdev->dev, &dev_attr_profile_led_green); // Profile/Macro LED Green + device_remove_file(&hdev->dev, &dev_attr_profile_led_blue); // Profile/Macro LED Blue + break; + + case USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_2019_ADV: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + break; + + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_fn_toggle); // Sets whether FN is requires for F-Keys + break; + + case USB_DEVICE_ID_RAZER_BLADE_QHD: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017: + case USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_fn_toggle); // Sets whether FN is requires for F-Keys + device_remove_file(&hdev->dev, &dev_attr_logo_led_state); // Enable/Disable the logo + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016: + case USB_DEVICE_ID_RAZER_BLADE_2018: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + case USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021: + case USB_DEVICE_ID_RAZER_BLADE_14_2021: + case USB_DEVICE_ID_RAZER_BLADE_17_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2022: + case USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022: + case USB_DEVICE_ID_RAZER_BLADE_14_2023: + case USB_DEVICE_ID_RAZER_BLADE_15_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2023: + case USB_DEVICE_ID_RAZER_BLADE_16_2025: + case USB_DEVICE_ID_RAZER_BLADE_18_2023: + case USB_DEVICE_ID_RAZER_BLADE_14_2024: + case USB_DEVICE_ID_RAZER_BLADE_18_2024: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_logo_led_state); // Enable/Disable the logo + break; + + case USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG: + case USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + + case USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); // Wave effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_starlight); // Starlight effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); // Reactive effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); // Set LED matrix + device_remove_file(&hdev->dev, &dev_attr_game_led_state); // Enable game mode & LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_state); // Enable macro LED + device_remove_file(&hdev->dev, &dev_attr_macro_led_effect); // Change macro LED effect (static, flashing) + break; + } + } else if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD) { + device_remove_file(&hdev->dev, &dev_attr_key_super); + device_remove_file(&hdev->dev, &dev_attr_key_alt_tab); + device_remove_file(&hdev->dev, &dev_attr_key_alt_f4); + } + + hid_hw_stop(hdev); + kfree(dev); + dev_info(&intf->dev, "Razer Device disconnected\n"); +} + +/** + * Setup input device keybit mask + */ +static void razer_setup_key_bits(struct input_dev *input) +{ + __set_bit(EV_KEY, input->evbit); + + // Chroma keys + __set_bit(RAZER_MACRO_KEY, input->keybit); + __set_bit(RAZER_GAME_KEY, input->keybit); + __set_bit(RAZER_BRIGHTNESS_DOWN, input->keybit); + __set_bit(RAZER_BRIGHTNESS_UP, input->keybit); +} + +/** + * Setup the input device now that its been added to our struct + */ +static int razer_input_configured(struct hid_device *hdev, struct hid_input *hi) +{ + razer_setup_key_bits(hi->input); + return 0; +} + +/** + * Device ID mapping table + */ +static const struct hid_device_id razer_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORBWEAVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NOSTROMO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_QHD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_2018) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_2018_BASE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_2019_ADV) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_2019_BASE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_PRO_2019) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_TARTARUS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_TARTARUS_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_TARTARUS_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA_V3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA_V3_ALT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA_V3_X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CYNOSA_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CYNOSA_LITE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_CYNOSA_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_2019) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ORNATA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ANANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_LATE_2016) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_PRO_2017) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_TE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_MINI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BOOK_2020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_14_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_17_2022) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_14_2022) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_14_2023) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_15_2023) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_14_2024) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_16_2023) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_16_2025) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_18_2023) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BLADE_18_2024) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(hid, razer_devices); + +/** + * Describes the contents of the driver + */ +static struct hid_driver razer_kbd_driver = { + .name = "razerkbd", + .id_table = razer_devices, + .input_mapping = razer_kbd_input_mapping, + .probe = razer_kbd_probe, + .remove = razer_kbd_disconnect, + .event = razer_event, + .raw_event = razer_raw_event, + .input_configured = razer_input_configured, +}; + +module_hid_driver(razer_kbd_driver); diff --git a/openrazer/driver/razerkbd_driver.h b/openrazer/driver/razerkbd_driver.h new file mode 100644 index 00000000..cd8d35fa --- /dev/null +++ b/openrazer/driver/razerkbd_driver.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015 Tim Theede + * 2015 Terri Cain + */ + +#ifndef __HID_RAZER_KBD_H +#define __HID_RAZER_KBD_H + +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2012 0x010D +// 2011 or so edition, see https://web.archive.org/web/20111113132427/http://store.razerzone.com:80/store/razerusa/en_US/pd/productID.235228400/categoryId.49136200/parentCategoryId.35156900 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH_EDITION 0x010E +#define USB_DEVICE_ID_RAZER_ANANSI 0x010F +#define USB_DEVICE_ID_RAZER_NOSTROMO 0x0111 +#define USB_DEVICE_ID_RAZER_ORBWEAVER 0x0113 +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_ESSENTIAL 0x0118 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2013 0x011A +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_STEALTH 0x011B +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_TE_2014 0x011C +#define USB_DEVICE_ID_RAZER_TARTARUS 0x0201 +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT 0x0202 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA 0x0203 +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA 0x0204 +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH 0x0205 +#define USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA 0x0207 +#define USB_DEVICE_ID_RAZER_TARTARUS_CHROMA 0x0208 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_TE 0x0209 +#define USB_DEVICE_ID_RAZER_BLADE_QHD 0x020F +#define USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2016 0x0210 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH 0x0211 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016 0x0214 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA 0x0216 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE 0x0217 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_X_CHROMA_TE 0x021A +#define USB_DEVICE_ID_RAZER_ORNATA_CHROMA 0x021E +#define USB_DEVICE_ID_RAZER_ORNATA 0x021F +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2016 0x0220 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2 0x0221 +#define USB_DEVICE_ID_RAZER_BLADE_LATE_2016 0x0224 +#define USB_DEVICE_ID_RAZER_BLADE_PRO_2017 0x0225 +#define USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE 0x0226 +#define USB_DEVICE_ID_RAZER_HUNTSMAN 0x0227 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE 0x0228 +#define USB_DEVICE_ID_RAZER_CYNOSA_CHROMA 0x022A +#define USB_DEVICE_ID_RAZER_TARTARUS_V2 0x022B +#define USB_DEVICE_ID_RAZER_CYNOSA_CHROMA_PRO 0x022C +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH_MID_2017 0x022D +#define USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD 0x022F +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2017 0x0232 +#define USB_DEVICE_ID_RAZER_BLADE_2018 0x0233 +#define USB_DEVICE_ID_RAZER_BLADE_PRO_2019 0x0234 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE 0x0235 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL 0x0237 +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH_2019 0x0239 +#define USB_DEVICE_ID_RAZER_BLADE_2019_ADV 0x023A +#define USB_DEVICE_ID_RAZER_BLADE_2018_BASE 0x023B +#define USB_DEVICE_ID_RAZER_CYNOSA_LITE 0x023F +#define USB_DEVICE_ID_RAZER_BLADE_2018_MERCURY 0x0240 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_2019 0x0241 +#define USB_DEVICE_ID_RAZER_HUNTSMAN_TE 0x0243 +#define USB_DEVICE_ID_RAZER_BLADE_MID_2019_MERCURY 0x0245 +#define USB_DEVICE_ID_RAZER_BLADE_2019_BASE 0x0246 +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2019 0x024A +#define USB_DEVICE_ID_RAZER_BLADE_ADV_LATE_2019 0x024B +#define USB_DEVICE_ID_RAZER_BLADE_PRO_LATE_2019 0x024C +#define USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019 0x024D +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V3 0x024E +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH_EARLY_2020 0x0252 +#define USB_DEVICE_ID_RAZER_BLADE_15_ADV_2020 0x0253 +#define USB_DEVICE_ID_RAZER_BLADE_EARLY_2020_BASE 0x0255 +#define USB_DEVICE_ID_RAZER_BLADE_PRO_EARLY_2020 0x0256 +#define USB_DEVICE_ID_RAZER_HUNTSMAN_MINI 0x0257 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI 0x0258 +#define USB_DEVICE_ID_RAZER_BLADE_STEALTH_LATE_2020 0x0259 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRED 0x025A +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_PRO_WIRELESS 0x025C +#define USB_DEVICE_ID_RAZER_ORNATA_V2 0x025D +#define USB_DEVICE_ID_RAZER_CYNOSA_V2 0x025E +#define USB_DEVICE_ID_RAZER_HUNTSMAN_V2_ANALOG 0x0266 +#define USB_DEVICE_ID_RAZER_BLADE_LATE_2020_BASE 0x0268 +#define USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_JP 0x0269 +#define USB_DEVICE_ID_RAZER_BOOK_2020 0x026A +#define USB_DEVICE_ID_RAZER_HUNTSMAN_V2_TENKEYLESS 0x026B +#define USB_DEVICE_ID_RAZER_HUNTSMAN_V2 0x026C +#define USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2021 0x026D +#define USB_DEVICE_ID_RAZER_BLADE_17_PRO_EARLY_2021 0x026E +#define USB_DEVICE_ID_RAZER_BLADE_15_BASE_EARLY_2021 0x026F +#define USB_DEVICE_ID_RAZER_BLADE_14_2021 0x0270 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_MINI_WIRELESS 0x0271 +#define USB_DEVICE_ID_RAZER_BLADE_15_ADV_MID_2021 0x0276 +#define USB_DEVICE_ID_RAZER_BLADE_17_PRO_MID_2021 0x0279 +#define USB_DEVICE_ID_RAZER_BLADE_15_BASE_2022 0x027A +#define USB_DEVICE_ID_RAZER_HUNTSMAN_MINI_ANALOG 0x0282 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V4 0x0287 +#define USB_DEVICE_ID_RAZER_BLADE_15_ADV_EARLY_2022 0x028A +#define USB_DEVICE_ID_RAZER_BLADE_17_2022 0x028B +#define USB_DEVICE_ID_RAZER_BLADE_14_2022 0x028C +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_PRO 0x028D +#define USB_DEVICE_ID_RAZER_ORNATA_V3_ALT 0x028F +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRELESS 0x0290 +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_WIRED 0x0292 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_X 0x0293 +#define USB_DEVICE_ID_RAZER_ORNATA_V3_X 0x0294 +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_V2 0x0295 +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRELESS 0x0296 +#define USB_DEVICE_ID_RAZER_DEATHSTALKER_V2_PRO_TKL_WIRED 0x0298 +#define USB_DEVICE_ID_RAZER_BLADE_14_2023 0x029D +#define USB_DEVICE_ID_RAZER_BLADE_15_2023 0x029E +#define USB_DEVICE_ID_RAZER_BLADE_16_2023 0x029F +#define USB_DEVICE_ID_RAZER_BLADE_18_2023 0x02A0 +#define USB_DEVICE_ID_RAZER_ORNATA_V3 0x02A1 +#define USB_DEVICE_ID_RAZER_ORNATA_V3_X_ALT 0x02A2 +#define USB_DEVICE_ID_RAZER_ORNATA_V3_TENKEYLESS 0x02A3 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V4_75PCT 0x02A5 +#define USB_DEVICE_ID_RAZER_HUNTSMAN_V3_PRO 0x02A6 +#define USB_DEVICE_ID_RAZER_BLADE_14_2024 0x02B6 +#define USB_DEVICE_ID_RAZER_BLADE_18_2024 0x02B8 +#define USB_DEVICE_ID_RAZER_BLADE_16_2025 0x02C6 +#define USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK 0x0A24 + +/* Each keyboard report has 90 bytes*/ +#define RAZER_BLACKWIDOW_REPORT_LEN 0x5A + +#define RAZER_BLACKWIDOW_CHROMA_WAVE_DIRECTION_LEFT 2 +#define RAZER_BLACKWIDOW_CHROMA_WAVE_DIRECTION_RIGHT 1 + +#define RAZER_BLACKWIDOW_CHROMA_CHANGE_EFFECT 0x0A + +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_NONE 0 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_WAVE 1 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_REACTIVE 2 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_BREATH 3 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_SPECTRUM 4 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_CUSTOM 5 // draw frame +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_STATIC 6 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_CLEAR_ROW 8 + +#define RAZER_BLACKWIDOW_ULTIMATE_2016_EFFECT_STARLIGHT 0x19 + +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_SET_KEYS 9 //update profile needs to be called after setting keys to reflect changes +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_RESET 10 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_UNKNOWN 11 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_UNKNOWN2 12 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_UNKNOWN3 13 +#define RAZER_BLACKWIDOW_CHROMA_EFFECT_UNKNOWN4 14 + +#define RAZER_BLACKWIDOW_CHROMA_ROW_LEN 0x16 +#define RAZER_BLACKWIDOW_CHROMA_ROWS_NUM 6 + +#define RAZER_STEALTH_ROW_LEN 0x10 +#define RAZER_STEALTH_ROWS_NUM 6 + +#define RAZER_BLACKWIDOW_CHROMA_WAIT_MS 1 +#define RAZER_BLACKWIDOW_CHROMA_WAIT_MIN_US 600 +#define RAZER_BLACKWIDOW_CHROMA_WAIT_MAX_US 800 + +#define RAZER_BLACKWIDOW_V3_WIRELESS_WAIT_MIN_US 4900 +#define RAZER_BLACKWIDOW_V3_WIRELESS_WAIT_MAX_US 5000 + +#define RAZER_DEATHSTALKER_V2_WIRELESS_WAIT_MIN_US 4900 +#define RAZER_DEATHSTALKER_V2_WIRELESS_WAIT_MAX_US 5000 + +#define RAZER_FIREFLY_WAIT_MIN_US 900 +#define RAZER_FIREFLY_WAIT_MAX_US 1000 + +struct razer_kbd_device { + struct usb_device *usb_dev; + struct mutex lock; + unsigned char usb_interface_protocol; + unsigned short usb_vid; + unsigned short usb_pid; + + unsigned int fn_on; + DECLARE_BITMAP(pressed_fn, KEY_CNT); + + unsigned char block_keys[3]; + unsigned char left_alt_on; +}; + +#endif diff --git a/openrazer/driver/razerkraken_driver.c b/openrazer/driver/razerkraken_driver.c new file mode 100644 index 00000000..b1e6ec11 --- /dev/null +++ b/openrazer/driver/razerkraken_driver.c @@ -0,0 +1,885 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Terri Cain + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "razerkraken_driver.h" +#include "razercommon.h" + +/* + * Version Information + */ +#define DRIVER_DESC "Razer Keyboard Device Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE(DRIVER_LICENSE); + +/** + * Print report to syslog + */ +/* +static void print_erroneous_kraken_request_report(struct razer_kraken_request_report* report, char* driver_name, char* message) +{ + printk(KERN_WARNING "%s: %s. Report ID: %02x dest: %02x length: %02x ADDR: %02x%02x Args: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x .\n", + driver_name, + message, + report->report_id, + report->destination, + report->length, + report->addr_h, + report->addr_l, + report->arguments[0], report->arguments[1], report->arguments[2], report->arguments[3], report->arguments[4], report->arguments[5], + report->arguments[6], report->arguments[7], report->arguments[8], report->arguments[9], report->arguments[10], report->arguments[11], + report->arguments[12], report->arguments[13], report->arguments[14], report->arguments[15]); +} +*/ + +static int razer_kraken_send_control_msg(struct usb_device *usb_dev,struct razer_kraken_request_report* report, unsigned char skip) +{ + uint request = HID_REQ_SET_REPORT; // 0x09 + uint request_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT; // 0x21 + uint value = 0x0204; + uint index = 0x0003; + uint size = 37; + char *buf; + int len; + + buf = kmemdup(report, size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + // Send usb control message + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + request, // Request U8 + request_type, // RequestType U8 + value, // Value U16 + index, // Index U16 + buf, // Data void* data + size, // Length U16 + USB_CTRL_SET_TIMEOUT); // Int + + // Wait + if(skip != 1) { + msleep(report->length * 15); + } + + kfree(buf); + if(len!=size) + printk(KERN_WARNING "razer driver: Device data transfer failed.\n"); + + return ((len < 0) ? len : ((len != size) ? -EIO : 0)); +} + +/** + * Get a request report + * + * report_id - The type of report + * destination - where data is going (like ram) + * length - amount of data + * address - where to write data to + */ +static struct razer_kraken_request_report get_kraken_request_report(unsigned char report_id, unsigned char destination, unsigned char length, unsigned short address) +{ + struct razer_kraken_request_report report; + memset(&report, 0, sizeof(struct razer_kraken_request_report)); + + report.report_id = report_id; + report.destination = destination; + report.length = length; + report.addr_h = (address >> 8); + report.addr_l = (address & 0xFF); + + return report; +} + +/** + * Get a union containing the effect bitfield + */ +static union razer_kraken_effect_byte get_kraken_effect_byte(void) +{ + union razer_kraken_effect_byte effect_byte; + memset(&effect_byte, 0, sizeof(union razer_kraken_effect_byte)); + + return effect_byte; +} + +/** + * Get the current effect + */ +static unsigned char get_current_effect(struct device *dev) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report report = get_kraken_request_report(0x04, 0x00, 0x01, device->led_mode_address); + int is_mutex_locked = mutex_is_locked(&device->lock); + unsigned char result = 0; + + // Lock if there isn't already a lock, otherwise skip, essentially emulate a rentrant lock + if(is_mutex_locked == 0) { + mutex_lock(&device->lock); + } + + device->data[0] = 0x00; + razer_kraken_send_control_msg(device->usb_dev, &report, 1); + msleep(25); // Sleep 20ms + + // Check for actual data + if(device->data[0] == 0x05) { + result = device->data[1]; + } else { + printk(KERN_CRIT "razerkraken: Did not manage to get report\n"); + } + + // Unlock if there isn't already a lock (as there would be by now), otherwise skip as reusing existing lock + if(is_mutex_locked == 0) { + mutex_unlock(&device->lock); + } + + return result; +} + +static unsigned int get_rgb_from_addr(struct device *dev, unsigned short address, unsigned char len, char* buf) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report report = get_kraken_request_report(0x04, 0x00, len, address); + int is_mutex_locked = mutex_is_locked(&device->lock); + unsigned char written = 0; + + // Lock if there isn't already a lock, otherwise skip, essentially emulate a rentrant lock + if(is_mutex_locked == 0) { + mutex_lock(&device->lock); + } + + device->data[0] = 0x00; + razer_kraken_send_control_msg(device->usb_dev, &report, 1); + msleep(25); // Sleep 20ms + + // Check for actual data + if(device->data[0] == 0x05) { + //printk(KERN_CRIT "razerkraken: Got %02x%02x%02x %02x\n", device->data[1], device->data[2], device->data[3], device->data[4]); + memcpy(&buf[0], &device->data[1], len); + written = len; + } else { + printk(KERN_CRIT "razerkraken: Did not manage to get report\n"); + } + + // Unlock if there isn't already a lock (as there would be by now), otherwise skip as reusing existing lock + if(is_mutex_locked == 0) { + mutex_unlock(&device->lock); + } + + return written; +} + +/** + * Read device file "version" + * + * Returns a string + */ +static ssize_t razer_attr_read_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", DRIVER_VERSION); +} + +/** + * Read device file "device_type" + * + * Returns friendly string of device type + */ +static ssize_t razer_attr_read_device_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + + char *device_type; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC: + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC_ALT: + device_type = "Razer Kraken 7.1\n"; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN: + device_type = "Razer Kraken 7.1 Chroma\n"; // Rainie + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + device_type = "Razer Kraken 7.1 V2\n"; // Kylie + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + device_type = "Razer Kraken Ultimate\n"; + break; + + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2: + device_type = "Razer Kraken Kitty V2\n"; + break; + + default: + device_type = "Unknown Device\n"; + } + + return sprintf(buf, device_type); +} + +/** + * Write device file "test" + * + * Does nothing + */ +static ssize_t razer_attr_write_test(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +/** + * Read device file "test" + * + * Returns a string + */ +static ssize_t razer_attr_read_test(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "\n"); +} + +/** + * Write device file "mode_spectrum" + * + * Specrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report report = get_kraken_request_report(0x04, 0x40, 0x01, device->led_mode_address); + union razer_kraken_effect_byte effect_byte = get_kraken_effect_byte(); + + // Spectrum Cycling | ON + effect_byte.bits.on_off_static = 1; + effect_byte.bits.spectrum_cycling = 1; + + report.arguments[0] = effect_byte.value; + + // Lock access to sending USB as adhering to the razer len*15ms delay + mutex_lock(&device->lock); + razer_kraken_send_control_msg(device->usb_dev, &report, 0); + mutex_unlock(&device->lock); + + return count; +} + +/** + * Write device file "mode_none" + * + * None effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report report = get_kraken_request_report(0x04, 0x40, 0x01, device->led_mode_address); + union razer_kraken_effect_byte effect_byte = get_kraken_effect_byte(); + + // Spectrum Cycling | OFF + effect_byte.bits.on_off_static = 0; + effect_byte.bits.spectrum_cycling = 0; + + report.arguments[0] = effect_byte.value; + + // Lock access to sending USB as adhering to the razer len*15ms delay + mutex_lock(&device->lock); + razer_kraken_send_control_msg(device->usb_dev, &report, 0); + mutex_unlock(&device->lock); + + return count; +} + +/** + * Write device file "mode_static" + * + * Static effect mode is activated whenever the file is written to with 3 bytes + */ +static ssize_t razer_attr_write_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report rgb_report = get_kraken_request_report(0x04, 0x40, count, device->breathing_address[0]); + struct razer_kraken_request_report effect_report = get_kraken_request_report(0x04, 0x40, 0x01, device->led_mode_address); + union razer_kraken_effect_byte effect_byte = get_kraken_effect_byte(); + + if (count != 3 && count != 4) { + printk(KERN_WARNING "razerkraken: Static mode only accepts RGB (3byte) or RGB with intensity (4byte)\n"); + return -EINVAL; + } + + rgb_report.arguments[0] = buf[0]; + rgb_report.arguments[1] = buf[1]; + rgb_report.arguments[2] = buf[2]; + + if(count == 4) { + rgb_report.arguments[3] = buf[3]; + } + + // ON/Static + effect_byte.bits.on_off_static = 1; + effect_report.arguments[0] = effect_byte.value; + + // Lock sending of the 2 commands + mutex_lock(&device->lock); + + // Basically Kraken Classic doesn't take RGB arguments so only do it for the KrakenV1,V2,Ultimate + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN: + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2: + razer_kraken_send_control_msg(device->usb_dev, &rgb_report, 0); + break; + } + + // Send Set static command + razer_kraken_send_control_msg(device->usb_dev, &effect_report, 0); + mutex_unlock(&device->lock); + + return count; +} + +/** + * Write device file "mode_custom" + * + * Custom effect mode is activated whenever the file is written to with 3 bytes + */ +static ssize_t razer_attr_write_matrix_effect_custom(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report rgb_report = get_kraken_request_report(0x04, 0x40, count, device->custom_address); + struct razer_kraken_request_report effect_report = get_kraken_request_report(0x04, 0x40, 0x01, device->led_mode_address); + union razer_kraken_effect_byte effect_byte = get_kraken_effect_byte(); + + if(count != 3 && count != 4) { + printk(KERN_WARNING "razerkraken: Custom mode only accepts RGB (3byte) or RGB with intensity (4byte)\n"); + return -EINVAL; + } + + rgb_report.arguments[0] = buf[0]; + rgb_report.arguments[1] = buf[1]; + rgb_report.arguments[2] = buf[2]; + + if(count == 4) { + rgb_report.arguments[3] = buf[3]; + } + + // ON/Static + effect_byte.bits.on_off_static = 1; + effect_report.arguments[0] = effect_byte.value; + + // Lock sending of the 2 commands + mutex_lock(&device->lock); + razer_kraken_send_control_msg(device->usb_dev, &rgb_report, 1); + + razer_kraken_send_control_msg(device->usb_dev, &effect_report, 1); + mutex_unlock(&device->lock); + + return count; +} + +/** + * Read device file "mode_static" + * + * Returns 4 bytes for config + */ +static ssize_t razer_attr_read_matrix_effect_static(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + return get_rgb_from_addr(dev, device->breathing_address[0], 0x04, buf); +} + +/** + * Read device file "mode_custom" + * + * Returns 4 bytes for config + */ +static ssize_t razer_attr_read_matrix_effect_custom(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + return get_rgb_from_addr(dev, device->custom_address, 0x04, buf); +} + +/** + * Write device file "mode_breath" + * + * Breathing effect mode is activated whenever the file is written to with 3,6 or 9 bytes + */ +static ssize_t razer_attr_write_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report effect_report = get_kraken_request_report(0x04, 0x40, 0x01, device->led_mode_address); + union razer_kraken_effect_byte effect_byte = get_kraken_effect_byte(); + + // Short circuit here as rainie only does breathing1 + if(device->usb_pid == USB_DEVICE_ID_RAZER_KRAKEN && count != 3) { + printk(KERN_WARNING "razerkraken: Breathing mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + if(count == 3) { + struct razer_kraken_request_report rgb_report = get_kraken_request_report(0x04, 0x40, 0x03, device->breathing_address[0]); + + rgb_report.arguments[0] = buf[0]; + rgb_report.arguments[1] = buf[1]; + rgb_report.arguments[2] = buf[2]; + + // ON/Static + effect_byte.bits.on_off_static = 1; + effect_byte.bits.single_colour_breathing = 1; + effect_byte.bits.sync = 1; + effect_report.arguments[0] = effect_byte.value; + + // Lock sending of the 2 commands + mutex_lock(&device->lock); + razer_kraken_send_control_msg(device->usb_dev, &rgb_report, 0); + + razer_kraken_send_control_msg(device->usb_dev, &effect_report, 0); + mutex_unlock(&device->lock); + } else if(count == 6) { + struct razer_kraken_request_report rgb_report = get_kraken_request_report(0x04, 0x40, 0x03, device->breathing_address[1]); + struct razer_kraken_request_report rgb_report2 = get_kraken_request_report(0x04, 0x40, 0x03, device->breathing_address[1]+4); // Address the 2nd set of colours + + rgb_report.arguments[0] = buf[0]; + rgb_report.arguments[1] = buf[1]; + rgb_report.arguments[2] = buf[2]; + rgb_report2.arguments[0] = buf[3]; + rgb_report2.arguments[1] = buf[4]; + rgb_report2.arguments[2] = buf[5]; + + // ON/Static + effect_byte.bits.on_off_static = 1; + effect_byte.bits.two_colour_breathing = 1; + effect_byte.bits.sync = 1; + effect_report.arguments[0] = effect_byte.value; + + // Lock sending of the 2 commands + mutex_lock(&device->lock); + razer_kraken_send_control_msg(device->usb_dev, &rgb_report, 0); + + razer_kraken_send_control_msg(device->usb_dev, &rgb_report2, 0); + + razer_kraken_send_control_msg(device->usb_dev, &effect_report, 0); + mutex_unlock(&device->lock); + + } else if(count == 9) { + struct razer_kraken_request_report rgb_report = get_kraken_request_report(0x04, 0x40, 0x03, device->breathing_address[2]); + struct razer_kraken_request_report rgb_report2 = get_kraken_request_report(0x04, 0x40, 0x03, device->breathing_address[2]+4); // Address the 2nd set of colours + struct razer_kraken_request_report rgb_report3 = get_kraken_request_report(0x04, 0x40, 0x03, device->breathing_address[2]+8); // Address the 3rd set of colours + + rgb_report.arguments[0] = buf[0]; + rgb_report.arguments[1] = buf[1]; + rgb_report.arguments[2] = buf[2]; + rgb_report2.arguments[0] = buf[3]; + rgb_report2.arguments[1] = buf[4]; + rgb_report2.arguments[2] = buf[5]; + rgb_report3.arguments[0] = buf[6]; + rgb_report3.arguments[1] = buf[7]; + rgb_report3.arguments[2] = buf[8]; + + // ON/Static + effect_byte.bits.on_off_static = 1; + effect_byte.bits.three_colour_breathing = 1; + effect_byte.bits.sync = 1; + effect_report.arguments[0] = effect_byte.value; + + // Lock sending of the 2 commands + mutex_lock(&device->lock); + razer_kraken_send_control_msg(device->usb_dev, &rgb_report, 0); + + razer_kraken_send_control_msg(device->usb_dev, &rgb_report2, 0); + + razer_kraken_send_control_msg(device->usb_dev, &rgb_report3, 0); + + razer_kraken_send_control_msg(device->usb_dev, &effect_report, 0); + mutex_unlock(&device->lock); + + } else { + printk(KERN_WARNING "razerkraken: Breathing mode only accepts RGB (3byte), RGB RGB (6byte) or RGB RGB RGB (9byte)\n"); + return -EINVAL; + } + + return count; +} + +/** + * Read device file "mode_breath" + * + * Returns 4, 8, 12 bytes for config + */ +static ssize_t razer_attr_read_matrix_effect_breath(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + union razer_kraken_effect_byte effect_byte; + unsigned char num_colours = 1; + + effect_byte.value = get_current_effect(dev); + + if(effect_byte.bits.two_colour_breathing == 1) { + num_colours = 2; + } else if(effect_byte.bits.three_colour_breathing == 1) { + num_colours = 3; + } + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2: + switch(num_colours) { + case 3: + return get_rgb_from_addr(dev, device->breathing_address[2], 0x0C, buf); + break; + case 2: + return get_rgb_from_addr(dev, device->breathing_address[1], 0x08, buf); + break; + default: + return get_rgb_from_addr(dev, device->breathing_address[0], 0x04, buf); + break; + } + break; + + case USB_DEVICE_ID_RAZER_KRAKEN: + return get_rgb_from_addr(dev, device->breathing_address[0], 0x04, buf); + break; + + default: + printk(KERN_WARNING "razerkraken: Unknown device\n"); + return -EINVAL; + } +} + +/** + * Read device file "serial" + * + * Returns a string + */ +static ssize_t razer_attr_read_device_serial(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report report = get_kraken_request_report(0x04, 0x20, 0x16, 0x7f00); + + // Basically some simple caching + // Also skips going to device if it doesn't contain the serial + if(device->serial[0] == '\0') { + + mutex_lock(&device->lock); + device->data[0] = 0x00; + razer_kraken_send_control_msg(device->usb_dev, &report, 1); + msleep(25); // Sleep 20ms + + // Check for actual data + if(device->data[0] == 0x05) { + // Serial is present + memcpy(&device->serial[0], &device->data[1], 22); + device->serial[22] = '\0'; + } else { + printk(KERN_CRIT "razerkraken: Did not manage to get serial from device, using XX01 instead\n"); + device->serial[0] = 'X'; + device->serial[1] = 'X'; + device->serial[2] = '0'; + device->serial[3] = '1'; + device->serial[4] = '\0'; + } + mutex_unlock(&device->lock); + + } + + return sprintf(buf, "%s\n", &device->serial[0]); +} + +/** + * Read device file "get_firmware_version" + * + * Returns a string + */ +static ssize_t razer_attr_read_firmware_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_kraken_device *device = dev_get_drvdata(dev); + struct razer_kraken_request_report report = get_kraken_request_report(0x04, 0x20, 0x02, 0x0030); + + // Basically some simple caching + if(device->firmware_version[0] != 1) { + + mutex_lock(&device->lock); + device->data[0] = 0x00; + razer_kraken_send_control_msg(device->usb_dev, &report, 1); + msleep(25); // Sleep 20ms + + // Check for actual data + if(device->data[0] == 0x05) { + // Serial is present + device->firmware_version[0] = 1; + device->firmware_version[1] = device->data[1]; + device->firmware_version[2] = device->data[2]; + } else { + printk(KERN_CRIT "razerkraken: Did not manage to get firmware version from device, using v9.99 instead\n"); + device->firmware_version[0] = 1; + device->firmware_version[1] = 0x09; + device->firmware_version[2] = 0x99; + } + mutex_unlock(&device->lock); + } + + return sprintf(buf, "v%x.%x\n", device->firmware_version[1], device->firmware_version[2]); +} + +/** + * Read device file "matrix_current_effect" + * + * Returns a string + */ +static ssize_t razer_attr_read_matrix_current_effect(struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned char current_effect = get_current_effect(dev); + + return sprintf(buf, "%02x\n", current_effect); +} + +/** + * Write device file "device_mode" + */ +static ssize_t razer_attr_write_device_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +/** + * Read device file "device_mode" + * + * Returns a string + */ +static ssize_t razer_attr_read_device_mode(struct device *dev, struct device_attribute *attr, char *buf) +{ + buf[0] = 0x00; + buf[1] = 0x00; + + return 2; +} + +/** + * Set up the device driver files + + * + * Read only is 0444 + * Write only is 0220 + * Read and write is 0664 + */ + +static DEVICE_ATTR(test, 0660, razer_attr_read_test, razer_attr_write_test); +static DEVICE_ATTR(version, 0440, razer_attr_read_version, NULL); +static DEVICE_ATTR(device_type, 0440, razer_attr_read_device_type, NULL); +static DEVICE_ATTR(device_serial, 0440, razer_attr_read_device_serial, NULL); +static DEVICE_ATTR(device_mode, 0660, razer_attr_read_device_mode, razer_attr_write_device_mode); +static DEVICE_ATTR(firmware_version, 0440, razer_attr_read_firmware_version, NULL); + +static DEVICE_ATTR(matrix_current_effect, 0440, razer_attr_read_matrix_current_effect, NULL); +static DEVICE_ATTR(matrix_effect_none, 0220, NULL, razer_attr_write_matrix_effect_none); +static DEVICE_ATTR(matrix_effect_spectrum, 0220, NULL, razer_attr_write_matrix_effect_spectrum); +static DEVICE_ATTR(matrix_effect_static, 0660, razer_attr_read_matrix_effect_static, razer_attr_write_matrix_effect_static); +static DEVICE_ATTR(matrix_effect_custom, 0660, razer_attr_read_matrix_effect_custom, razer_attr_write_matrix_effect_custom); +static DEVICE_ATTR(matrix_effect_breath, 0660, razer_attr_read_matrix_effect_breath, razer_attr_write_matrix_effect_breath); + +static void razer_kraken_init(struct razer_kraken_device *dev, struct usb_interface *intf) +{ + struct usb_device *usb_dev = interface_to_usbdev(intf); + unsigned int rand_serial = 0; + + // Initialise mutex + mutex_init(&dev->lock); + // Setup values + dev->usb_dev = usb_dev; + dev->usb_interface_protocol = intf->cur_altsetting->desc.bInterfaceProtocol; + dev->usb_vid = usb_dev->descriptor.idVendor; + dev->usb_pid = usb_dev->descriptor.idProduct; + + switch(dev->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2: + dev->led_mode_address = KYLIE_SET_LED_ADDRESS; + dev->custom_address = KYLIE_CUSTOM_ADDRESS_START; + dev->breathing_address[0] = KYLIE_BREATHING1_ADDRESS_START; + dev->breathing_address[1] = KYLIE_BREATHING2_ADDRESS_START; + dev->breathing_address[2] = KYLIE_BREATHING3_ADDRESS_START; + break; + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC: + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC_ALT: + case USB_DEVICE_ID_RAZER_KRAKEN: + dev->led_mode_address = RAINIE_SET_LED_ADDRESS; + dev->custom_address = RAINIE_CUSTOM_ADDRESS_START; + dev->breathing_address[0] = RAINIE_BREATHING1_ADDRESS_START; + + // Get a "random" integer + get_random_bytes(&rand_serial, sizeof(unsigned int)); + sprintf(&dev->serial[0], "HN%015u", rand_serial); + break; + } +} + +/** + * Probe method is ran whenever a device is binded to the driver + */ +static int razer_kraken_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int retval = 0; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct razer_kraken_device *dev = NULL; + + dev = kzalloc(sizeof(struct razer_kraken_device), GFP_KERNEL); + if(dev == NULL) { + dev_err(&intf->dev, "out of memory\n"); + return -ENOMEM; + } + + // Init data + razer_kraken_init(dev, intf); + + if(dev->usb_interface_protocol == USB_INTERFACE_PROTOCOL_NONE) { + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_version); // Get driver version + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_test); // Test mode + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_type); // Get string of device type + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_serial); // Get string of device serial + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_firmware_version); // Get string of device fw version + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_mode); // Get device mode + + switch(dev->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC: + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC_ALT: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_current_effect); // Get current effect + break; + case USB_DEVICE_ID_RAZER_KRAKEN: + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_current_effect); // Get current effect + break; + } + } + + dev_set_drvdata(&hdev->dev, dev); + + if(hid_parse(hdev)) { + hid_err(hdev, "parse failed\n"); + goto exit_free; + } + + if (hid_hw_start(hdev, HID_CONNECT_DEFAULT)) { + hid_err(hdev, "hw start failed\n"); + goto exit_free; + } + + usb_disable_autosuspend(usb_dev); + + return 0; + +exit_free: + kfree(dev); + return retval; +} + +/** + * Unbind function + */ +static void razer_kraken_disconnect(struct hid_device *hdev) +{ + struct razer_kraken_device *dev; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + + dev = hid_get_drvdata(hdev); + + if(dev->usb_interface_protocol == USB_INTERFACE_PROTOCOL_NONE) { + device_remove_file(&hdev->dev, &dev_attr_version); // Get driver version + device_remove_file(&hdev->dev, &dev_attr_test); // Test mode + device_remove_file(&hdev->dev, &dev_attr_device_type); // Get string of device type + device_remove_file(&hdev->dev, &dev_attr_device_serial); // Get string of device serial + device_remove_file(&hdev->dev, &dev_attr_firmware_version); // Get string of device fw version + device_remove_file(&hdev->dev, &dev_attr_device_mode); // Get device mode + + switch(dev->usb_pid) { + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC: + case USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC_ALT: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_current_effect); // Get current effect + break; + + case USB_DEVICE_ID_RAZER_KRAKEN: + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2: + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); // No effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); // Spectrum effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); // Static effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); // Custom effect + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); // Breathing effect + device_remove_file(&hdev->dev, &dev_attr_matrix_current_effect); // Get current effect + break; + } + } + + hid_hw_stop(hdev); + kfree(dev); + dev_info(&intf->dev, "Razer Device disconnected\n"); +} + +static int razer_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) +{ + struct razer_kraken_device *device = dev_get_drvdata(&hdev->dev); + + //printk(KERN_WARNING "razerkraken: Got raw message %d\n", size); + + if(size == 33) { // Should be a response to a Control packet + memcpy(&device->data[0], &data[0], size); + + } else { + printk(KERN_WARNING "razerkraken: Got raw message, length: %d\n", size); + } + + return 0; +} + +/** + * Device ID mapping table + */ +static const struct hid_device_id razer_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC_ALT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_KRAKEN) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_KRAKEN_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(hid, razer_devices); + +/** + * Describes the contents of the driver + */ +static struct hid_driver razer_kraken_driver = { + .name = "razerkraken", + .id_table = razer_devices, + .probe = razer_kraken_probe, + .remove = razer_kraken_disconnect, + .raw_event = razer_raw_event +}; + +module_hid_driver(razer_kraken_driver); diff --git a/openrazer/driver/razerkraken_driver.h b/openrazer/driver/razerkraken_driver.h new file mode 100644 index 00000000..30865bf9 --- /dev/null +++ b/openrazer/driver/razerkraken_driver.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015 Terri Cain + */ + +#ifndef __HID_RAZER_KRAKEN_H +#define __HID_RAZER_KRAKEN_H + +#define USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC 0x0501 +#define USB_DEVICE_ID_RAZER_KRAKEN 0x0504 // Codename Rainie +#define USB_DEVICE_ID_RAZER_KRAKEN_CLASSIC_ALT 0x0506 +#define USB_DEVICE_ID_RAZER_KRAKEN_V2 0x0510 // Codename Kylie +#define USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE 0x0527 +#define USB_DEVICE_ID_RAZER_KRAKEN_KITTY_V2 0x0560 + +#define USB_INTERFACE_PROTOCOL_NONE 0 + +// #define RAZER_KRAKEN_V2_REPORT_LEN ? + +struct razer_kraken_device { + struct usb_device *usb_dev; + struct mutex lock; + unsigned char usb_interface_protocol; + unsigned short usb_pid; + unsigned short usb_vid; + + // Will be set with the correct address for setting LED mode for each device + unsigned short led_mode_address; + unsigned short custom_address; + unsigned short breathing_address[3]; + + char serial[23]; + // 3 Bytes, first byte is whether fw version is collected, 2nd byte is major version, 3rd is minor, should be printed out in hex form as are bcd + unsigned char firmware_version[3]; + + u8 data[33]; + +}; + +union razer_kraken_effect_byte { + unsigned char value; + struct razer_kraken_effect_byte_bits { + unsigned char on_off_static :1; + unsigned char single_colour_breathing :1; + unsigned char spectrum_cycling :1; + unsigned char sync :1; + unsigned char two_colour_breathing :1; + unsigned char three_colour_breathing :1; + } bits; +}; + +/* + * Should wait 15ms per write to EEPROM + * + * Report ID: + * 0x04 - Output ID for memory access + * 0x05 - Input ID for memory access result + * + * Destination: + * 0x20 - Read data from EEPROM + * 0x40 - Write data to RAM + * 0x00 - Read data from RAM + * + * Address: + * RAM - Both + * 0x1189 - Custom effect Colour1 Red + * 0x118A - Custom effect Colour1 Green + * 0x118B - Custom effect Colour1 Blue + * 0x118C - Custom effect Colour1 Intensity + * + * RAM - Kylie + * 0x172D - Set LED Effect, see note 1 + * 0x1741 - Static/Breathing1 Colour1 Red + * 0x1742 - Static/Breathing1 Colour1 Green + * 0x1743 - Static/Breathing1 Colour1 Blue + * 0x1744 - Static/Breathing1 Colour1 Intensity + * + * 0x1745 - Breathing2 Colour1 Red + * 0x1746 - Breathing2 Colour1 Green + * 0x1747 - Breathing2 Colour1 Blue + * 0x1748 - Breathing2 Colour1 Intensity + * 0x1749 - Breathing2 Colour2 Red + * 0x174A - Breathing2 Colour2 Green + * 0x174B - Breathing2 Colour2 Blue + * 0x174C - Breathing2 Colour2 Intensity + * + * 0x174D - Breathing3 Colour1 Red + * 0x174E - Breathing3 Colour1 Green + * 0x174F - Breathing3 Colour1 Blue + * 0x1750 - Breathing3 Colour1 Intensity + * 0x1751 - Breathing3 Colour2 Red + * 0x1752 - Breathing3 Colour2 Green + * 0x1753 - Breathing3 Colour2 Blue + * 0x1754 - Breathing3 Colour2 Intensity + * 0x1755 - Breathing3 Colour3 Red + * 0x1756 - Breathing3 Colour3 Green + * 0x1757 - Breathing3 Colour3 Blue + * 0x1758 - Breathing3 Colour3 Intensity + * + * RAM - Rainie + * 0x1008 - Set LED Effect, see note 1 + * 0x15DE - Static/Breathing1 Colour1 Red + * 0x15DF - Static/Breathing1 Colour1 Green + * 0x15E0 - Static/Breathing1 Colour1 Blue + * 0x15E1 - Static/Breathing1 Colour1 Intensity + * + * EEPROM + * 0x0030 - Firmware version, 2 byted BCD + * 0x7f00 - Serial Number - 22 Bytes + * + * + * Note 1: + * Takes one byte which is a bitfield (0 being the rightmost byte 76543210) + * - Bit 0 = LED ON/OFF = 1/0 Static + * - Bit 1 = Single Colour Breathing ON/OFF, 1/0 + * - Bit 2 = Spectrum Cycling + * - Bit 3 = Sync = 1 + * - Bit 4 = 2 Colour breathing ON/OFF = 1/0 + * - Bit 5 = 3 Colour breathing ON/OFF = 1/0 + * E.g. + * 7 6 5 4 3 2 1 0 + * 128 64 32 16 8 4 2 1 + * ===================================================== + * 0 0 0 0 0 1 0 1 0x05 Spectrum Cycling on + * + * Note 2: + * Razer Kraken Classic uses 0x1008 for Logo LED on off. + * */ + +#define KYLIE_SET_LED_ADDRESS 0x172D +#define RAINIE_SET_LED_ADDRESS 0x1008 + +#define KYLIE_CUSTOM_ADDRESS_START 0x1189 +#define RAINIE_CUSTOM_ADDRESS_START 0x1189 + +#define KYLIE_BREATHING1_ADDRESS_START 0x1741 +#define RAINIE_BREATHING1_ADDRESS_START 0x15DE + +#define KYLIE_BREATHING2_ADDRESS_START 0x1745 +#define KYLIE_BREATHING3_ADDRESS_START 0x174D + +struct razer_kraken_request_report { + unsigned char report_id; + unsigned char destination; + unsigned char length; + unsigned char addr_h; + unsigned char addr_l; + unsigned char arguments[32]; +}; + +struct razer_kraken_response_report { + unsigned char report_id; + unsigned char arguments[36]; +}; + +#endif diff --git a/openrazer/driver/razermouse_driver.c b/openrazer/driver/razermouse_driver.c new file mode 100644 index 00000000..b01b4e8d --- /dev/null +++ b/openrazer/driver/razermouse_driver.c @@ -0,0 +1,7955 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Terri Cain + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "razermouse_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/* + * Version Information + */ +#define DRIVER_DESC "Razer Mouse Device Driver" + +/* REL_HWHEEL_HI_RES was added in Linux 5.0, so define ourselves for older kernels + * See also https://git.kernel.org/torvalds/c/52ea899 */ +#ifndef REL_HWHEEL_HI_RES +#define REL_HWHEEL_HI_RES 0x0c +#endif + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE(DRIVER_LICENSE); + +/** + * Send report to the mouse + */ +// Add this global variable at the top +int razer_debug_enabled = 0; + +// Enhanced debug version of razer_send_payload +static struct razer_report razer_send_payload(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report) +{ + IOReturn retval = -1; + struct razer_report response_report = {0}; + + // Debug: Print request details + if (razer_debug_enabled) { + printf("=== SENDING COMMAND ===\n"); + printf("Command Class: 0x%02x\n", request_report->command_class); + printf("Command ID: 0x%02x\n", request_report->command_id.id); + printf("Data Size: %d\n", request_report->data_size); + printf("Transaction ID: 0x%02x\n", request_report->transaction_id.id); + + printf("Request Data: "); + for(int i = 0; i < request_report->data_size && i < 20; i++) { + printf("%02x ", request_report->arguments[i]); + } + printf("\n"); + + printf("Full Request Packet: "); + unsigned char *packet = (unsigned char*)request_report; + for(int i = 0; i < sizeof(struct razer_report); i++) { + printf("%02x ", packet[i]); + if((i + 1) % 16 == 0) printf("\n"); + } + printf("\n========================\n"); + } + + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(usb_dev, request_report, &response_report); + + // Debug: Print response details + if (razer_debug_enabled) { + printf("=== RESPONSE ===\n"); + printf("Return Value: %d\n", retval); + printf("Response Status: 0x%02x\n", response_report.status); + + if(retval == 0) { + printf("Response Data: "); + for(int i = 0; i < response_report.data_size && i < 20; i++) { + printf("%02x ", response_report.arguments[i]); + } + printf("\n"); + } + printf("================\n\n"); + } + + if(retval == 0) { + // Check the packet number, class and command are the same + if(response_report.remaining_packets != request_report->remaining_packets || + response_report.command_class != request_report->command_class || + response_report.command_id.id != request_report->command_id.id) { + printf("Response doesn't match request (mousedock)\n"); + } else if (response_report.status == RAZER_CMD_BUSY) { + if (razer_debug_enabled) printf("Device is busy (mousedock)\n"); + } else if (response_report.status == RAZER_CMD_FAILURE) { + printf("Command failed (mousedock)\n"); + } else if (response_report.status == RAZER_CMD_NOT_SUPPORTED) { + printf("Command not supported (mousedock)\n"); + } else if (response_report.status == RAZER_CMD_TIMEOUT) { + printf("Command timed out (mousedock)\n"); + } else if (response_report.status == RAZER_CMD_SUCCESSFUL && razer_debug_enabled) { + printf("Command successful!\n"); + } + } else { + printf("Invalid Report Length (mousedock)\n"); + } + + return response_report; +} + +// Add a function to enable/disable debug from Node.js +void razer_set_debug(int enabled) { + razer_debug_enabled = enabled; + printf("Razer debug %s\n", enabled ? "enabled" : "disabled"); +} + +/* + * Specific functions for ancient devices + * + */ +static int deathadder3_5g_set_led_state(struct razer_mouse_device *device, unsigned char led_id, bool enabled) +{ + switch (led_id) { + case SCROLL_WHEEL_LED: + if (enabled) { + device->da3_5g.leds |= 0x02; + } else { + device->da3_5g.leds &= ~(0x02); + } + break; + + case LOGO_LED: + if (enabled) { + device->da3_5g.leds |= 0x01; + } else { + device->da3_5g.leds &= ~(0x01); + } + break; + + default: + printk(KERN_WARNING "razermouse: Invalid led_id on DeathAdder 3.5G\n"); + return -EINVAL; + } + + mutex_lock(&device->lock); + razer_send_control_msg_old_device(device->usb_dev, &device->da3_5g, 0x10, 0x00, 4, 3000, 3000); + mutex_unlock(&device->lock); + + return 0; +} + +static void deathadder3_5g_set_poll_rate(struct razer_mouse_device *device, unsigned short poll_rate) +{ + switch(poll_rate) { + case 1000: + device->da3_5g.poll = 1; + break; + case 500: + device->da3_5g.poll = 2; + break; + case 125: + device->da3_5g.poll = 3; + break; + default: // 500 + device->da3_5g.poll = 2; + break; + } + + mutex_lock(&device->lock); + razer_send_control_msg_old_device(device->usb_dev, &device->da3_5g, 0x10, 0x00, 4, 3000, 3000); + mutex_unlock(&device->lock); +} + +static void deathadder3_5g_set_dpi(struct razer_mouse_device *device, unsigned short dpi) +{ + switch(dpi) { + case 450: + device->da3_5g.dpi = 4; + break; + case 900: + device->da3_5g.dpi = 3; + break; + case 1800: + device->da3_5g.dpi = 2; + break; + case 3500: + default: + device->da3_5g.dpi = 1; + break; + } + + mutex_lock(&device->lock); + razer_send_control_msg_old_device(device->usb_dev, &device->da3_5g, 0x10, 0x00, 4, 3000, 3000); + mutex_unlock(&device->lock); +} + +static int orochi_2011_set_led_state(struct razer_mouse_device *device, unsigned char led_id, bool enabled) +{ + switch (led_id) { + case SCROLL_WHEEL_LED: + if (enabled) { + device->orochi2011.led |= 0b00000001; + } else { + device->orochi2011.led &= 0b11111110; + } + break; + case LOGO_LED: + if (enabled) { + device->orochi2011.led |= 0b00000010; + } else { + device->orochi2011.led &= 0b11111101; + } + break; + default: + printk(KERN_WARNING "razermouse: Invalid led_id on Orochi 2011\n"); + return -EINVAL; + } + + return 0; +} + +/* + * New functions + */ + +/** + * Read device file "version" + * + * Returns a string + */ +static ssize_t razer_attr_read_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", DRIVER_VERSION); +} + +/** + * Read device file "device_type" + * + * Returns friendly string of device type + */ +static ssize_t razer_attr_read_device_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + + char *device_type; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + device_type = "Razer DeathAdder 3.5G\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + device_type = "Razer DeathAdder 3.5G Black\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + device_type = "Razer Mamba 2012 (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + device_type = "Razer Mamba 2012 (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + device_type = "Razer Mamba (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + device_type = "Razer Mamba (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + device_type = "Razer Mamba Tournament Edition\n"; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS: + device_type = "Razer Abyssus 2014\n"; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + device_type = "Razer Abyssus 1800\n"; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + device_type = "Razer Abyssus 2000\n"; + break; + + case USB_DEVICE_ID_RAZER_IMPERATOR: + device_type = "Razer Imperator 2012\n"; + break; + + case USB_DEVICE_ID_RAZER_OUROBOROS: + device_type = "Razer Ouroboros\n"; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + device_type = "Razer Orochi 2011\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + device_type = "Razer DeathAdder 2013\n"; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2013: + device_type = "Razer Orochi 2013\n"; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + device_type = "Razer Orochi (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + device_type = "Razer DeathAdder Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + device_type = "Razer Naga Hex (Red)\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX: + device_type = "Razer Naga Hex\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA: + device_type = "Razer Naga\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_2012: + device_type = "Razer Naga 2012\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + device_type = "Razer Naga Epic\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_2014: + device_type = "Razer Naga 2014\n"; + break; + + case USB_DEVICE_ID_RAZER_TAIPAN: + device_type = "Razer Taipan\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + device_type = "Razer Naga Hex V2\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + device_type = "Razer Naga Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + device_type = "Razer Naga X\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + device_type = "Razer DeathAdder Elite\n"; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + device_type = "Razer Abyssus V2\n"; + break; + + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + device_type = "Razer Diamondback Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + device_type = "Razer DeathAdder 3500\n"; + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + device_type = "Razer Lancehead (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + device_type = "Razer Lancehead (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + device_type = "Razer Lancehead Tournament Edition\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + device_type = "Razer Mamba Elite\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + device_type = "Razer DeathAdder Essential\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + device_type = "Razer DeathAdder Essential (2021)\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + device_type = "Razer Naga Trinity\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + device_type = "Razer DeathAdder 1800\n"; + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + device_type = "Razer Lancehead Wireless (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + device_type = "Razer Lancehead Wireless (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + device_type = "Razer Mamba Wireless (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + device_type = "Razer Mamba Wireless (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + device_type = "Razer Abyssus Elite (D.Va Edition)\n"; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + device_type = "Razer Abyssus Essential\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + device_type = "Razer DeathAdder Essential (White Edition)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER: + device_type = "Razer Viper\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_MINI: + device_type = "Razer Viper Mini\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + device_type = "Razer Viper Mini Signature Edition (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + device_type = "Razer Viper Mini Signature Edition (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + device_type = "Razer Viper Ultimate (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + device_type = "Razer Viper Ultimate (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + device_type = "Razer Viper V2 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + device_type = "Razer Viper V2 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK: + device_type = "Razer Basilisk\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL: + device_type = "Razer Basilisk Essential\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + device_type = "Razer Basilisk Ultimate (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + device_type = "Razer Basilisk Ultimate (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V2: + device_type = "Razer Basilisk V2\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3: + device_type = "Razer Basilisk V3\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + device_type = "Razer DeathAdder V2\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + device_type = "Razer DeathAdder V2 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + device_type = "Razer DeathAdder V2 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + device_type = "Razer DeathAdder V3\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + device_type = "Razer DeathAdder V3 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + device_type = "Razer DeathAdder V3 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + device_type = "Razer DeathAdder V3 HyperSpeed (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + device_type = "Razer DeathAdder V3 HyperSpeed (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + device_type = "Razer HyperPolling Wireless Dongle\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + device_type = "Razer Basilisk V3 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + device_type = "Razer Basilisk V3 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + device_type = "Razer Basilisk V3 35K\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + device_type = "Razer Basilisk V3 Pro 35K (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + device_type = "Razer Basilisk V3 Pro 35K (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + device_type = "Razer DeathAdder V2 Mini\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + device_type = "Razer DeathAdder 2000\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + device_type = "Razer DeathAdder V2 X HyperSpeed\n"; + break; + + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + device_type = "Razer Atheris (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + device_type = "Razer Basilisk X HyperSpeed\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + device_type = "Razer Naga Left-Handed Edition 2020\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + device_type = "Razer Naga Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + device_type = "Razer Naga Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + device_type = "Razer Viper 8KHz\n"; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + device_type = "Razer Orochi V2 (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + device_type = "Razer Orochi V2 (Bluetooth)\n"; + break; + + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + device_type = "Razer Pro Click (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + device_type = "Razer Pro Click (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + device_type = "Razer Naga Epic Chroma\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + device_type = "Razer Naga Epic Chroma Dock\n"; + break; + + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + device_type = "Razer Pro Click Mini (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + device_type = "Razer DeathAdder V2 Lite\n"; + break; + + case USB_DEVICE_ID_RAZER_COBRA: + device_type = "Razer Cobra\n"; + break; + + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + device_type = "Razer Cobra Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + device_type = "Razer Cobra Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + device_type = "Razer Viper V3 HyperSpeed\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + device_type = "Razer Naga V2 HyperSpeed (Receiver)\n"; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + device_type = "Razer Basilisk V3 X HyperSpeed\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + device_type = "Razer Viper V3 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + device_type = "Razer Viper V3 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + device_type = "Razer Naga V2 Pro (Wired)\n"; + break; + + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + device_type = "Razer Naga V2 Pro (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + device_type = "Razer Pro Click V2 Vertical Edition (Wireless)\n"; + break; + + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + device_type = "Razer Pro Click V2 Vertical Edition (Wired)\n"; + break; + + default: + device_type = "Unknown Device\n"; + } + + return sprintf(buf, device_type); +} + +/** + * Read device file "get_firmware_version" + * + * Returns a string + */ +static ssize_t razer_attr_read_firmware_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response_report = {0}; + + // Debug: Print request details + if (razer_debug_enabled) { + printf("=== SENDING COMMAND ===\n"); + printf("Command Class: 0x%02x\n", request_report->command_class); + printf("Command ID: 0x%02x\n", request_report->command_id.id); + printf("Data Size: %d\n", request_report->data_size); + printf("Transaction ID: 0x%02x\n", request_report->transaction_id.id); + + printf("Request Data: "); + for(int i = 0; i < request_report->data_size && i < 20; i++) { + + request = razer_chroma_standard_get_firmware_version(); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_OROCHI_2011: // Orochi 2011 doesn't have FW + return sprintf(buf, "v%d.%d\n", 9, 99); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: // DA don't think supports fw, its proper old + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + return sprintf(buf, "v%d.%d\n", 0x01, 0x00); + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: firmware_version not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "v%d.%d\n", response.arguments[0], response.arguments[1]); +} + +/** + * Write device file "test" + * + * Writes the colour segments on the mouse. + */ +static ssize_t razer_attr_write_test(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned char enabled = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_set_led_state(VARSTORE, LOGO_LED, enabled); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_none" + * + * No effect is activated whenever this file is written to + */ +static ssize_t razer_attr_write_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: // TODO: this is probably wrong? + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: // TODO: this is probably wrong? + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + request = razer_chroma_standard_matrix_effect_none(); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_none not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_custom" + * + * Sets the mouse to custom mode whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_custom(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: // TODO look into this think its extended effects + request = razer_chroma_standard_matrix_effect_custom_frame(NOSTORE); + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_custom_frame(); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + request = razer_chroma_standard_matrix_effect_custom_frame(NOSTORE); + request.transaction_id.id = 0x80; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request = razer_chroma_standard_matrix_effect_custom_frame(NOSTORE); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_custom not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_static" + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +static ssize_t razer_attr_write_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 3) { + printk(KERN_WARNING "razermouse: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + // Some sort of mode switcher required after initialization and before color switching + request = get_razer_report(0x0f, 0x02, 0x06); + request.arguments[0] = 0x00; + request.arguments[1] = 0x00; + request.arguments[2] = 0x08; + request.arguments[3] = 0x00; + request.arguments[4] = 0x00; + request.arguments[5] = 0x00; + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + request = razer_naga_trinity_effect_static((struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_static not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_wave" + * + * When 1 is written (as a character, 0x31) the wave effect is displayed moving up the mouse + * if 2 is written (0x32) then the wave effect goes down + */ +static ssize_t razer_attr_write_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned char direction = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_wave not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_spectrum" + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + request = razer_chroma_mouse_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_spectrum not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_reactive" + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char speed; + + if (count != 4) { + printk(KERN_WARNING "razermouse: Reactive only accepts Speed, RGB (4byte)\n"); + return -EINVAL; + } + + speed = (unsigned char)buf[0]; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_mouse_extended_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_reactive not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "mode_breath" + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +static ssize_t razer_attr_write_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_mouse_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x1f; + break; + + case 6: // Dual colour mode + request = razer_chroma_mouse_extended_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + request.transaction_id.id = 0x1f; + break; + + default: // "Random" colour mode + request = razer_chroma_mouse_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0x1f; + break; + } + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_breath not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "get_serial" + * + * Returns a string + */ +static ssize_t razer_attr_read_device_serial(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + char serial_string[23]; + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_serial(); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_OROCHI_2011: + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: // Doesn't have proper serial + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + return sprintf(buf, "%s\n", &device->serial[0]); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + request.transaction_id.id = 0x08; + break; + + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: device_serial not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + strncpy(&serial_string[0], &response.arguments[0], 22); + serial_string[22] = '\0'; + + return sprintf(buf, "%s\n", &serial_string[0]); +} + +/** + * Read device file "get_battery" + * + * Returns an integer which needs to be scaled from 0-255 -> 0-100 + */ +static ssize_t razer_attr_read_charge_level(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_battery_level(); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: charge_level not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[1]); +} + +/** + * Read device file "is_charging" + * + * Returns 0 when not charging, 1 when charging + */ +static ssize_t razer_attr_read_charge_status(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_charging_status(); + + switch (device->usb_pid) { + // Wireless mice that don't support is_charging + // Use AA batteries + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + return sprintf(buf, "0\n"); + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: charge_status not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[1]); +} + +/** + * Write device file "set_charging_effect" + * + * Sets charging effect. + */ +static ssize_t razer_attr_write_charge_effect(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 1) { + printk(KERN_WARNING "razermouse: Incorrect number of bytes for setting the charging effect\n"); + return -EINVAL; + } + + request = razer_chroma_misc_set_dock_charge_type(buf[0]); + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: charge_effect not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "set_charging_colour" + * + * Sets charging colour using 3 RGB bytes + */ +static ssize_t razer_attr_write_charge_colour(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + // First enable static charging effect + request = razer_chroma_misc_set_dock_charge_type(0x01); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + if (count != 3) { + printk(KERN_WARNING "razermouse: Charging colour mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + request = razer_chroma_standard_set_led_rgb(NOSTORE, BATTERY_LED, (struct razer_rgb*)&buf[0]); + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: charge_colour not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "poll_rate" + * + * Returns a string + */ +static ssize_t razer_attr_read_poll_rate(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned short polling_rate = 0; + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + switch(device->da3_5g.poll) { + case 0x01: + polling_rate = 1000; + break; + case 0x02: + polling_rate = 500; + break; + case 0x03: + polling_rate = 125; + break; + } + return sprintf(buf, "%d\n", polling_rate); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_misc_get_polling_rate(); + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_misc_get_polling_rate(); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + request = razer_chroma_misc_get_polling_rate2(); + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + switch(response.arguments[1]) { + case 0x01: + polling_rate = 8000; + break; + case 0x02: + polling_rate = 4000; + break; + case 0x04: + polling_rate = 2000; + break; + case 0x08: + polling_rate = 1000; + break; + case 0x10: + polling_rate = 500; + break; + case 0x40: + polling_rate = 125; + break; + } + + return sprintf(buf, "%d\n", polling_rate); + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + request = razer_chroma_misc_get_polling_rate(); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: poll_rate not supported for this model\n"); + return -EINVAL; + } + + // XXX Clean up this special case for Orochi + if(device->usb_pid == USB_DEVICE_ID_RAZER_OROCHI_2011) { + response.arguments[0] = device->orochi2011.poll; + } else { + razer_send_payload(device, &request, &response); + } + + switch(response.arguments[0]) { + case 0x01: + polling_rate = 1000; + break; + case 0x02: + polling_rate = 500; + break; + case 0x08: + polling_rate = 125; + break; + } + + return sprintf(buf, "%d\n", polling_rate); +} + +/** + * Write device file "poll_rate" + * + * Sets the poll rate + */ +static ssize_t razer_attr_write_poll_rate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned short polling_rate = (unsigned short)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + deathadder3_5g_set_poll_rate(device, polling_rate); + return count; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + device->orochi2011.poll = polling_rate; + request = razer_chroma_misc_set_orochi2011_poll_dpi(device->orochi2011.poll, device->orochi2011.dpi, device->orochi2011.dpi); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_misc_set_polling_rate(polling_rate); + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_misc_set_polling_rate(polling_rate); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + request = razer_chroma_misc_set_polling_rate2(polling_rate, 0x00); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + request = razer_chroma_misc_set_polling_rate(polling_rate); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: poll_rate not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + // For certain devices, Razer sends each request once with 0x00 and once with 0x01 + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + request = razer_chroma_misc_set_polling_rate2(polling_rate, 0x01); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + break; + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + request = razer_chroma_misc_set_polling_rate2(polling_rate, 0x01); + request.transaction_id.id = 0x1F; + razer_send_payload(device, &request, &response); + break; + } + + return count; +} + +/** + * Write device file "matrix_brightness" + * + * Sets the brightness to the ASCII number written to this file. + */ + +static ssize_t razer_attr_write_matrix_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned char brightness = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + request = razer_chroma_misc_set_dock_brightness(brightness); + request.transaction_id.id = 0xFF; + break; + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: // TODO: Migrate to backlight_led_brightness + request = razer_chroma_standard_set_led_brightness(VARSTORE, BACKLIGHT_LED, brightness); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + request = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + request.transaction_id.id = 0x3F; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_brightness not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "matrix_brightness" + * + * Returns a string + */ +static ssize_t razer_attr_read_matrix_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char brightness_index = 0x02; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + request = razer_chroma_misc_get_dock_brightness(); + request.transaction_id.id = 0xFF; + brightness_index = 0x00; + break; + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: // TODO: Migrate to backlight_led_brightness + request = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, ZERO_LED); + request.transaction_id.id = 0x3F; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_brightness not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + if (response.status != RAZER_CMD_SUCCESSFUL) { + return 0; + } + // Brightness is at arg[0] for dock and arg[1] for led_brightness + return sprintf(buf, "%d\n", response.arguments[brightness_index]); +} + +/** + * Write device file "set_mouse_dpi" + * + * Sets the mouse DPI to the unsigned short integer written to this file. + */ +static ssize_t razer_attr_write_dpi(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned short dpi_x; + unsigned short dpi_y; + unsigned char dpi_x_byte; + unsigned char dpi_y_byte; + unsigned char varstore; + + // So far I think imperator uses varstore + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + if(count == 2) { + dpi_x = (buf[0] << 8) | (buf[1] & 0xFF); // TODO make convenience function + deathadder3_5g_set_dpi(device, dpi_x); + } else { + printk(KERN_WARNING "razermouse: DPI requires 2 bytes\n"); + return -EINVAL; + } + return count; + break; + + // Damn naga hex only uses 1 byte per x, y dpi + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + if(count == 1) { + dpi_x_byte = buf[0]; + dpi_y_byte = buf[0]; + } else if (count == 2) { + dpi_x_byte = buf[0]; + dpi_y_byte = buf[1]; + } else { + printk(KERN_WARNING "razermouse: DPI requires 1 byte or 2 bytes\n"); + return -EINVAL; + } + + request = razer_chroma_misc_set_dpi_xy_byte(dpi_x_byte, dpi_y_byte); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + return count; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + if(count == 1) { + dpi_x_byte = buf[0]; + dpi_y_byte = buf[0]; + } else if (count == 2) { + dpi_x_byte = buf[0]; + dpi_y_byte = buf[1]; + } else { + printk(KERN_WARNING "razermouse: DPI requires 1 byte or 2 bytes\n"); + return -EINVAL; + } + device->orochi2011.dpi = dpi_x_byte; + + request = razer_chroma_misc_set_orochi2011_poll_dpi(device->orochi2011.poll, dpi_x_byte, dpi_y_byte); + request.transaction_id.id = 0xFF; + razer_send_payload(device, &request, &response); + return count; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + varstore = VARSTORE; + break; + + default: + varstore = NOSTORE; + break; + } + + if (count != 2 && count != 4) { + printk(KERN_WARNING "razermouse: DPI requires 2 bytes or 4 bytes\n"); + return -EINVAL; + } + + if (count == 2) { + dpi_x = (buf[0] << 8) | (buf[1] & 0xFF); // TODO make convenience function + request = razer_chroma_misc_set_dpi_xy(varstore, dpi_x, dpi_x); + + } else if(count == 4) { + dpi_x = (buf[0] << 8) | (buf[1] & 0xFF); // Apparently the char buffer is rubbish, as buf[1] somehow can equal FFFFFF80???? + dpi_y = (buf[2] << 8) | (buf[3] & 0xFF); + + request = razer_chroma_misc_set_dpi_xy(varstore, dpi_x, dpi_y); + } + + switch(device->usb_pid) { // New devices set the device ID properly + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: dpi not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "dpi" + * + * Gets the mouse DPI to the unsigned short integer written to this file. + */ +static ssize_t razer_attr_read_dpi(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned short dpi_x; + unsigned short dpi_y; + + // So far I think imperator uses varstore + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + switch(device->da3_5g.dpi) { + case 0x04: + dpi_x = 450; + break; + case 0x03: + dpi_x = 900; + break; + case 0x02: + dpi_x = 1800; + break; + case 0x01: + default: + dpi_x = 3500; + break; + } + return sprintf(buf, "%u\n", dpi_x); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + return sprintf(buf, "%u:%u\n", device->orochi2011.dpi, device->orochi2011.dpi); + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + request = razer_chroma_misc_get_dpi_xy_byte(); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_misc_get_dpi_xy(NOSTORE); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_IMPERATOR: + request = razer_chroma_misc_get_dpi_xy(VARSTORE); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_misc_get_dpi_xy(NOSTORE); + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + request = razer_chroma_misc_get_dpi_xy(NOSTORE); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: dpi not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + // Byte, Byte for DPI not Short, Short + if (device->usb_pid == USB_DEVICE_ID_RAZER_NAGA_HEX || + device->usb_pid == USB_DEVICE_ID_RAZER_NAGA_HEX_RED || + device->usb_pid == USB_DEVICE_ID_RAZER_NAGA || + device->usb_pid == USB_DEVICE_ID_RAZER_NAGA_2012 || + device->usb_pid == USB_DEVICE_ID_RAZER_DEATHADDER_2013 || + device->usb_pid == USB_DEVICE_ID_RAZER_NAGA_EPIC || + device->usb_pid == USB_DEVICE_ID_RAZER_ABYSSUS_1800) { // NagaHex is crap uses only byte for dpi + dpi_x = response.arguments[0]; + dpi_y = response.arguments[1]; + } else { + dpi_x = (response.arguments[1] << 8) | (response.arguments[2] & 0xFF); // Apparently the char buffer is rubbish, as buf[1] somehow can equal FFFFFF80???? + dpi_y = (response.arguments[3] << 8) | (response.arguments[4] & 0xFF); + } + + return sprintf(buf, "%u:%u\n", dpi_x, dpi_y); +} + +/** + * Write device file "scroll_mode" + * + * Sets the scroll mode of the mouse. + */ +static ssize_t razer_attr_write_scroll_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned int scroll_mode; + + if (kstrtouint(buf, 0, &scroll_mode) < 0 || scroll_mode > 1) + return -EINVAL; + + request = razer_chroma_misc_set_scroll_mode(scroll_mode); + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "scroll_mode" + * + * Gets the scroll wheel mode from the mouse. + */ +static ssize_t razer_attr_read_scroll_mode(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_scroll_mode(); + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[1]); +} + +/** + * Write device file "scroll_acceleration" + * + * Sets the scroll acceleration mode of the mouse. + */ +static ssize_t razer_attr_write_scroll_acceleration(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + bool acceleration; + + if (kstrtobool(buf, &acceleration) < 0) + return -EINVAL; + + request = razer_chroma_misc_set_scroll_acceleration(acceleration); + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "scroll_acceleration" + * + * Gets the scroll acceleration mode of the mouse. + */ +static ssize_t razer_attr_read_scroll_acceleration(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_scroll_acceleration(); + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[1]); +} + +/** + * Write device file "scroll_smart_reel" + * + * Sets the scroll wheel "smart reel" mode of the mouse. + */ +static ssize_t razer_attr_write_scroll_smart_reel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + bool smart_reel; + + if (kstrtobool(buf, &smart_reel) < 0) + return -EINVAL; + + request = razer_chroma_misc_set_scroll_smart_reel(smart_reel); + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "scroll_smart_reel" + * + * Gets the scroll wheel "smart reel" state from the mouse. + */ +static ssize_t razer_attr_read_scroll_smart_reel(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_scroll_smart_reel(); + request.transaction_id.id = 0x1f; + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[1]); +} + +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" + * + * Sets the mouse DPI stage. + * The number of DPI stages is hard limited by RAZER_MOUSE_MAX_DPI_STAGES. + * + * Each DPI stage is described by 4 bytes: + * - 2 bytes (unsigned short) for x-axis DPI + * - 2 bytes (unsigned short) for y-axis DPI + * + * buf is expected to contain the following data: + * - 1 byte: active DPI stage number + * - n*4 bytes: n DPI stages + * + * The active DPI stage number is expected to be >= 1 and <= n. + * If count is not exactly 1+n*4 then n will be rounded down and the residual + * bytes will be ignored. + * + * Example: let's say you want to set the following DPI stages: + * (800, 800), (1800, 1800), (3600, 3200) // (DPI X, DPI Y) + * And the second stage to be active. + * + * You have to write to this file 1 byte and 6 unsigned shorts (big endian) = 13 bytes: + * Active stage: 2 + * DPIs: | 800 | 800 | 1800 | 1800 | 3600 | 3200 + * Bytes (hex): 02 03 20 03 02 07 08 07 08 0e 10 0c 80 + */ +static ssize_t razer_attr_write_dpi_stages(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned short dpi[2 * RAZER_MOUSE_MAX_DPI_STAGES] = {0}; + unsigned char stages_count = 0; + unsigned char active_stage; + size_t remaining = count; + + if (remaining < 5) { + printk(KERN_ALERT "razermouse: At least one DPI stage expected\n"); + return -EINVAL; + } + + active_stage = buf[0]; + remaining++; + buf++; + + if (active_stage < 1) { + printk(KERN_ALERT "razermouse: Invalid active DPI stage: %u < 1\n", active_stage); + return -EINVAL; + } + + while (stages_count < RAZER_MOUSE_MAX_DPI_STAGES && remaining >= 4) { + // DPI X + dpi[stages_count * 2] = (buf[0] << 8) | (buf[1] & 0xFF); + + // DPI Y + dpi[stages_count * 2 + 1] = (buf[2] << 8) | (buf[3] & 0xFF); + + stages_count += 1; + buf += 4; + remaining -= 4; + } + + if (active_stage > stages_count) { + printk(KERN_ALERT "razermouse: Invalid active DPI stage: %u > %u\n", active_stage, stages_count); + return -EINVAL; + } + + request = razer_chroma_misc_set_dpi_stages(VARSTORE, stages_count, active_stage, dpi); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_COBRA: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: dpi_stages not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + // Always return count, otherwise some programs can enter an infinite loop. + // Example: + // Program writes 7 bytes to dpi_stages. 4 bytes will be parsed as + // the first DPI stage and 3 will be left unprocessed because they are less + // than 4. The program will try to write the 3 bytes again but this + // function will always return 0, throwing the program into a loop. + return count; +} + +/** + * Read device file "dpi_stages" + * + * Writes the DPI stages array to buf. + * + * Each DPI stage is described by 4 bytes: + * - 2 bytes (unsigned short) for x-axis DPI + * - 2 bytes (unsigned short) for y-axis DPI + * + * Always writes 1+n*4 bytes: + * - 1 byte: active DPI stage number, >= 0 and <= n. + * - n*4 bytes: n DPI stages. + */ +static ssize_t razer_attr_read_dpi_stages(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char stages_count; + ssize_t count; // bytes written + unsigned int i; // iterator over stages_count + unsigned char *args; // pointer to the next dpi value in response.arguments + + request = razer_chroma_misc_get_dpi_stages(VARSTORE); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_COBRA: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: dpi_stages not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + // Response format (hex): + // 01 varstore + // 02 active DPI stage + // 04 number of stages = 4 + // + // 01 first DPI stage + // 03 20 first stage DPI X = 800 + // 03 20 first stage DPI Y = 800 + // 00 00 reserved + // + // 02 second DPI stage + // 07 08 second stage DPI X = 1800 + // 07 08 second stage DPI Y = 1800 + // 00 00 reserved + // + // 03 third DPI stage + // ... + + stages_count = response.arguments[2]; + + buf[0] = response.arguments[1]; + + count = 1; + args = response.arguments + 4; + for (i = 0; i < stages_count; i++) { + // Check that we don't read past response.data_size + if (args + 4 > response.arguments + response.data_size) { + break; + } + + memcpy(buf + count, args, 4); + count += 4; + args += 7; + } + + return count; +} + +/** + * Read device file "device_idle_time" + * + * Gets the time this device will go into powersave as a number of seconds. + */ +static ssize_t razer_attr_read_device_idle_time(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned short idle_time = 0; + + request = razer_chroma_misc_get_idle_time(); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: device_idle_time not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + idle_time = (response.arguments[0] << 8) | (response.arguments[1] & 0xFF); + return sprintf(buf, "%u\n", idle_time); +} + +/** + * Write device file "device_idle_time" + * + * Sets the idle time to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_device_idle_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned short idle_time = (unsigned short)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_set_idle_time(idle_time); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: device_idle_time not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "charge_low_threshold" + */ +static ssize_t razer_attr_read_charge_low_threshold(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_get_low_battery_threshold(); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: charge_low_threshold not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return sprintf(buf, "%d\n", response.arguments[0]); +} + +/** + * Write device file "charge_low_threshold" + * + * Sets the low battery blink threshold to the ASCII number written to this file. + */ +static ssize_t razer_attr_write_charge_low_threshold(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned char threshold = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_set_low_battery_threshold(threshold); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: charge_low_threshold not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "matrix_custom_frame" + * + * Format + * ROW_ID START_COL STOP_COL RGB... + */ +static ssize_t razer_attr_write_matrix_custom_frame(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + size_t offset = 0; + unsigned char row_id, start_col, stop_col; + size_t row_length; + + while(offset < count) { + if(offset + 3 > count) { + printk(KERN_ALERT "razermouse: Wrong Amount of data provided: Should be ROW_ID, START_COL, STOP_COL, N_RGB\n"); + return -EINVAL; + } + + row_id = buf[offset++]; + start_col = buf[offset++]; + stop_col = buf[offset++]; + + // Mouse only has 1 row, row0 (pseudo row as the command actually doesn't take rows) + if(row_id != 0) { + printk(KERN_ALERT "razermouse: Row ID must be 0\n"); + return -EINVAL; + } + + // Validate parameters + if(start_col > stop_col) { + printk(KERN_ALERT "razermouse: Start column (%u) is greater than end column (%u)\n", start_col, stop_col); + return -EINVAL; + } + + row_length = ((stop_col + 1) - start_col) * 3; + + // Make sure we actually got the data that was promised to us + if(count < offset + row_length) { + printk(KERN_ALERT "razermouse: Not enough RGB to fill row (expecting %lu bytes of RGB data, got %lu)\n", row_length, (count - 3)); + return -EINVAL; + } + + // printk(KERN_INFO "razermouse: Row ID: %u, Start: %u, Stop: %u, row length: %lu\n", row_id, start_col, stop_col, row_length); + + // Offset now at beginning of RGB data + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + request = razer_chroma_standard_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + request = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + request = razer_chroma_misc_one_row_set_custom_frame(start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0x80; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request = razer_chroma_misc_one_row_set_custom_frame(start_col, stop_col, (unsigned char*)&buf[offset]); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + request = razer_chroma_extended_matrix_set_custom_frame2(row_id, start_col, stop_col, (unsigned char*)&buf[offset], 0); + request.transaction_id.id = 0x1f; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_custom_frame not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + // *3 as its 3 bytes per col (RGB) + offset += row_length; + } + + return count; +} + +/** + * Write device file "device_mode" + */ +static ssize_t razer_attr_write_device_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 2) { + printk(KERN_WARNING "razerkbd: Device mode only takes 2 bytes.\n"); + return -EINVAL; + } + + request = razer_chroma_standard_set_device_mode(buf[0], buf[1]); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_OROCHI_2011: // Doesn't have device mode + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: // Doesn't support device mode, exit early + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + return count; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: device_mode not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "device_mode" + * + * Returns a string + */ +static ssize_t razer_attr_read_device_mode(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_standard_get_device_mode(); + + switch(device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: // Doesn't support device mode, exit early + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + case USB_DEVICE_ID_RAZER_OROCHI_2011: + return sprintf(buf, "%d:%d\n", 0, 0); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + request.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: device_mode not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + buf[0] = response.arguments[0]; + buf[1] = response.arguments[1]; + + return 2; +} + +/** + * Common function to handle sysfs read LED brightness for a given led + */ +static ssize_t razer_attr_read_led_brightness(struct device *dev, struct device_attribute *attr, char *buf, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + request = razer_chroma_standard_get_led_brightness(VARSTORE, led_id); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, led_id); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_extended_matrix_get_brightness(VARSTORE, led_id); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_OUROBOROS: + request = razer_chroma_standard_get_led_brightness(VARSTORE, led_id); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: led_brightness not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + printf("%02x ", request_report->arguments[i]); +} +printf("\n"); + +printf("Full Request Packet: "); +unsigned char *packet = (unsigned char*)request_report; +for(int i = 0; i < sizeof(struct razer_report); i++) { + printf("%02x ", packet[i]); + if((i + 1) % 16 == 0) printf("\n"); +} +printf("\n========================\n"); + } + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + request = razer_chroma_standard_set_led_brightness(VARSTORE, led_id, brightness); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_brightness(VARSTORE, led_id, brightness); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_extended_matrix_brightness(VARSTORE, led_id, brightness); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_OUROBOROS: + request = razer_chroma_standard_set_led_brightness(VARSTORE, led_id, brightness); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: led_brightness not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Read device file "scroll_led_brightness" + */ +static ssize_t razer_attr_read_scroll_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_led_brightness(dev, attr, buf, SCROLL_WHEEL_LED); +} + +/** + * Write device file "scroll_led_brightness" + */ +static ssize_t razer_attr_write_scroll_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_led_brightness(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Read device file "logo_led_brightness" + */ +static ssize_t razer_attr_read_logo_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_led_brightness(dev, attr, buf, LOGO_LED); +} + +/** + * Write device file "logo_led_brightness" + */ +static ssize_t razer_attr_write_logo_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_led_brightness(dev, attr, buf, count, LOGO_LED); +} + +/** + * Read device file "left_led_brightness" + */ +static ssize_t razer_attr_read_left_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_led_brightness(dev, attr, buf, LEFT_SIDE_LED); +} + +/** + * Write device file "left_led_brightness" + */ +static ssize_t razer_attr_write_left_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_led_brightness(dev, attr, buf, count, LEFT_SIDE_LED); +} + +/** + * Read device file "right_led_brightness" + */ +static ssize_t razer_attr_read_right_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_led_brightness(dev, attr, buf, RIGHT_SIDE_LED); +} + +/** + * Write device file "right_led_brightness" + */ +static ssize_t razer_attr_write_right_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_led_brightness(dev, attr, buf, count, RIGHT_SIDE_LED); +} + +/** + * Read device file "backlight_led_brightness" + */ +static ssize_t razer_attr_read_backlight_led_brightness(struct device *dev, struct device_attribute *attr, char *buf) +{ + return razer_attr_read_led_brightness(dev, attr, buf, BACKLIGHT_LED); +} + +/** + * Write device file "backlight_led_brightness" + */ +static ssize_t razer_attr_write_backlight_led_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_led_brightness(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_wave for a given led + */ +static ssize_t razer_attr_write_matrix_effect_wave_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned char direction = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, led_id, direction); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_wave(VARSTORE, led_id, direction); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request = razer_chroma_standard_matrix_effect_wave(direction); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_wave not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "scroll_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_scroll_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_spectrum for a given led + */ +static ssize_t razer_attr_write_matrix_effect_spectrum_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, true); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_effect(VARSTORE, led_id, CLASSIC_EFFECT_SPECTRUM); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + request = razer_chroma_mouse_extended_matrix_effect_spectrum(VARSTORE, led_id); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, led_id); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, led_id); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request = razer_chroma_standard_matrix_effect_spectrum(); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_spectrum not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "scroll_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_scroll_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_spectrum_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_reactive for a given led + */ +static ssize_t razer_attr_write_matrix_effect_reactive_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + unsigned char speed; + + if (count != 4) { + printk(KERN_WARNING "razermouse: Reactive only accepts Speed, RGB (4byte)\n"); + return -EINVAL; + } + + speed = (unsigned char)buf[0]; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + request = razer_chroma_mouse_extended_matrix_effect_reactive(VARSTORE, led_id, speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_extended_matrix_effect_reactive(VARSTORE, led_id, speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_reactive(VARSTORE, led_id, speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request = razer_chroma_standard_matrix_effect_reactive(speed, (struct razer_rgb*)&buf[1]); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_reactive not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "scroll_mode_reactive" (for extended mouse matrix effects) + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_scroll_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_reactive_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_breath for a given led + */ +static ssize_t razer_attr_write_matrix_effect_breath_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + if (count != 3) { + printk(KERN_WARNING "razermouse: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, true); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_rgb(VARSTORE, led_id, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_effect(VARSTORE, led_id, CLASSIC_EFFECT_BREATHING); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + /* Mono-color breath effect */ + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, true); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_effect(VARSTORE, led_id, CLASSIC_EFFECT_BREATHING); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_mouse_extended_matrix_effect_breathing_single(VARSTORE, led_id, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_mouse_extended_matrix_effect_breathing_dual(VARSTORE, led_id, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_mouse_extended_matrix_effect_breathing_random(VARSTORE, led_id); + break; + } + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + 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_ESSENTIAL: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, led_id, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, led_id, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, led_id); + break; + } + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + switch(count) { + case 3: // Single colour mode + request = razer_chroma_standard_matrix_effect_breathing_single((struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + request = razer_chroma_standard_matrix_effect_breathing_dual((struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + request = razer_chroma_standard_matrix_effect_breathing_random(); + break; + } + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_breath not supported for this model\n"); + return -EINVAL; + } + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request.transaction_id.id = 0x3f; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_breath not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "scroll_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +static ssize_t razer_attr_write_scroll_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_static for a given led + */ +static ssize_t razer_attr_write_matrix_effect_static_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 3) { + printk(KERN_WARNING "razermouse: Static mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, true); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_rgb(VARSTORE, led_id, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_effect(VARSTORE, led_id, CLASSIC_EFFECT_STATIC); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + request = razer_chroma_mouse_extended_matrix_effect_static(VARSTORE, led_id, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_extended_matrix_effect_static(VARSTORE, led_id, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, SCROLL_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request = razer_chroma_standard_matrix_effect_static((struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_static not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "scroll_mode_static" (for extended mouse matrix effects) + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +static ssize_t razer_attr_write_scroll_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_blinking for a given led + */ +static ssize_t razer_attr_write_matrix_effect_blinking_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + if (count != 3) { + printk(KERN_WARNING "razermouse: Blinking mode only accepts RGB (3byte)\n"); + return -EINVAL; + } + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, true); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_rgb(VARSTORE, led_id, (struct razer_rgb*)&buf[0]); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_effect(VARSTORE, led_id, CLASSIC_EFFECT_BLINKING); + request.transaction_id.id = 0x3F; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_blinking not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "scroll_matrix_effect_blinking" + */ +static ssize_t razer_attr_write_scroll_matrix_effect_blinking(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_blinking_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Write device file "logo_matrix_effect_blinking" + */ +static ssize_t razer_attr_write_logo_matrix_effect_blinking(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_blinking_common(dev, attr, buf, count, LOGO_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_none for a given led + */ +static ssize_t razer_attr_write_matrix_effect_none_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + deathadder3_5g_set_led_state(device, led_id, false); + return count; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + orochi_2011_set_led_state(device, led_id, false); + request = razer_chroma_misc_set_orochi2011_led(device->orochi2011.led); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, false); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + if (led_id == SCROLL_WHEEL_LED) { + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, false); + request.transaction_id.id = 0x3F; + } else { + request = razer_chroma_standard_matrix_effect_none(); + request.transaction_id.id = 0xFF; + } + break; + + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + request = razer_chroma_mouse_extended_matrix_effect_none(VARSTORE, led_id); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + 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_ESSENTIAL: + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, led_id); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + case USB_DEVICE_ID_RAZER_NAGA_X: + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA: + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + request = razer_chroma_extended_matrix_effect_none(VARSTORE, led_id); + request.transaction_id.id = 0x1f; + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + request = razer_chroma_standard_matrix_effect_none(); + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_none not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "scroll_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +static ssize_t razer_attr_write_scroll_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +/** + * Common function to handle sysfs write matrix_effect_on for a given led + */ +static ssize_t razer_attr_write_matrix_effect_on_common(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, unsigned char led_id) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + struct razer_report request = {0}; + struct razer_report response = {0}; + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + deathadder3_5g_set_led_state(device, led_id, true); + return count; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + orochi_2011_set_led_state(device, led_id, true); + request = razer_chroma_misc_set_orochi2011_led(device->orochi2011.led); + request.transaction_id.id = 0xFF; + break; + + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_2012: + case USB_DEVICE_ID_RAZER_ABYSSUS: + case USB_DEVICE_ID_RAZER_IMPERATOR: + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_TAIPAN: + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_OUROBOROS: + case USB_DEVICE_ID_RAZER_OROCHI_2013: + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, true); + request.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + /* Could also be called a mono-color static effect */ + request = razer_chroma_standard_set_led_state(VARSTORE, led_id, true); + request.transaction_id.id = 0x3F; + razer_send_payload(device, &request, &response); + + request = razer_chroma_standard_set_led_effect(VARSTORE, led_id, CLASSIC_EFFECT_STATIC); + request.transaction_id.id = 0x3F; + break; + + default: + printk(KERN_WARNING "razermouse: matrix_effect_none not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +static ssize_t razer_attr_write_logo_matrix_effect_on(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_on_common(dev, attr, buf, count, LOGO_LED); +} + +static ssize_t razer_attr_write_scroll_matrix_effect_on(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_on_common(dev, attr, buf, count, SCROLL_WHEEL_LED); +} + +static ssize_t razer_attr_write_backlight_matrix_effect_on(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_on_common(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Write device file "logo_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_logo_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, LOGO_LED); +} + +/** + * Write device file "logo_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_logo_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_spectrum_common(dev, attr, buf, count, LOGO_LED); +} + +/** + * Write device file "logo_mode_reactive" (for extended mouse matrix effects) + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_logo_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_reactive_common(dev, attr, buf, count, LOGO_LED); +} + +/** + * Write device file "logo_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +static ssize_t razer_attr_write_logo_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, LOGO_LED); +} + +/** + * Write device file "logo_mode_static" (for extended mouse matrix effects) + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +static ssize_t razer_attr_write_logo_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, LOGO_LED); +} + +/** + * Write device file "logo_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +static ssize_t razer_attr_write_logo_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, LOGO_LED); +} + +/** + * Write device file "left_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_left_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_right_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "left_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_left_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_spectrum_common(dev, attr, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_right_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_spectrum_common(dev, attr, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "left_mode_reactive" (for extended mouse matrix effects) + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_left_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_reactive_common(dev, attr, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_reactive" (for extended mouse matrix effects) + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_right_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_reactive_common(dev, attr, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "left_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +static ssize_t razer_attr_write_left_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +static ssize_t razer_attr_write_right_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "left_mode_static" (for extended mouse matrix effects) + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +static ssize_t razer_attr_write_left_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_static" (for extended mouse matrix effects) + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +static ssize_t razer_attr_write_right_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "left_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +static ssize_t razer_attr_write_left_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +static ssize_t razer_attr_write_right_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "backlight_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_backlight_matrix_effect_wave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_wave_common(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Write device file "backlight_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +static ssize_t razer_attr_write_backlight_matrix_effect_spectrum(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_spectrum_common(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Write device file "backlight_mode_reactive" (for extended mouse matrix effects) + * + * Sets reactive mode when this file is written to. A speed byte and 3 RGB bytes should be written + */ +static ssize_t razer_attr_write_backlight_matrix_effect_reactive(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_reactive_common(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Write device file "backlight_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +static ssize_t razer_attr_write_backlight_matrix_effect_breath(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_breath_common(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Write device file "backlight_mode_static" (for extended mouse matrix effects) + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +static ssize_t razer_attr_write_backlight_matrix_effect_static(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_static_common(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Write device file "backlight_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +static ssize_t razer_attr_write_backlight_matrix_effect_none(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return razer_attr_write_matrix_effect_none_common(dev, attr, buf, count, BACKLIGHT_LED); +} + +/** + * Write device file "hyperpolling_wireless_dongle_indicator_led_mode" + */ +static ssize_t razer_attr_write_hyperpolling_wireless_dongle_indicator_led_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned char mode = (unsigned char)simple_strtoul(buf, NULL, 10); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_set_hyperpolling_wireless_dongle_indicator_led_mode(mode); + + switch (device->usb_pid) { + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + request.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + request.transaction_id.id = 0xFF; + break; + + default: + printk(KERN_WARNING "razermouse: hyperpolling_wireless_dongle_indicator_led_mode not supported for this model\n"); + return -EINVAL; + } + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "hyperpolling_wireless_dongle_pair" + */ +static ssize_t razer_attr_write_hyperpolling_wireless_dongle_pair(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned int pid = (unsigned int)simple_strtoul(buf, NULL, 16); + struct razer_report request = {0}; + struct razer_report response = {0}; + + // Step 1: Put in pairing mode + request = razer_chroma_misc_set_hyperpolling_wireless_dongle_pair_step1(0x01); + request.transaction_id.id = 0x1F; + + razer_send_payload(device, &request, &response); + + // Step 2: Pair with PID + request = razer_chroma_misc_set_hyperpolling_wireless_dongle_pair_step2(pid); + request.transaction_id.id = 0x1F; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Write device file "hyperpolling_wireless_dongle_unpair" + */ +static ssize_t razer_attr_write_hyperpolling_wireless_dongle_unpair(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct razer_mouse_device *device = dev_get_drvdata(dev); + unsigned int pid = (unsigned int)simple_strtoul(buf, NULL, 16); + struct razer_report request = {0}; + struct razer_report response = {0}; + + request = razer_chroma_misc_set_hyperpolling_wireless_dongle_unpair(pid); + request.transaction_id.id = 0xFF; + + razer_send_payload(device, &request, &response); + + return count; +} + +/** + * Set up the device driver files + * + * Read-only is 0444 + * Write-only is 0220 + * Read/write is 0664 + */ + +static DEVICE_ATTR(version, 0440, razer_attr_read_version, NULL); +static DEVICE_ATTR(firmware_version, 0440, razer_attr_read_firmware_version, NULL); +static DEVICE_ATTR(test, 0220, NULL, razer_attr_write_test); +static DEVICE_ATTR(poll_rate, 0660, razer_attr_read_poll_rate, razer_attr_write_poll_rate); +static DEVICE_ATTR(dpi, 0660, razer_attr_read_dpi, razer_attr_write_dpi); +static DEVICE_ATTR(dpi_stages, 0660, razer_attr_read_dpi_stages, razer_attr_write_dpi_stages); + +static DEVICE_ATTR(device_type, 0440, razer_attr_read_device_type, NULL); +static DEVICE_ATTR(device_mode, 0660, razer_attr_read_device_mode, razer_attr_write_device_mode); +static DEVICE_ATTR(device_serial, 0440, razer_attr_read_device_serial, NULL); +static DEVICE_ATTR(device_idle_time, 0660, razer_attr_read_device_idle_time, razer_attr_write_device_idle_time); + +static DEVICE_ATTR(scroll_mode, 0660, razer_attr_read_scroll_mode, razer_attr_write_scroll_mode); +static DEVICE_ATTR(scroll_acceleration, 0660, razer_attr_read_scroll_acceleration, razer_attr_write_scroll_acceleration); +static DEVICE_ATTR(scroll_smart_reel, 0660, razer_attr_read_scroll_smart_reel, razer_attr_write_scroll_smart_reel); + +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_charge_level, NULL); +static DEVICE_ATTR(charge_status, 0440, razer_attr_read_charge_status, NULL); +static DEVICE_ATTR(charge_effect, 0220, NULL, razer_attr_write_charge_effect); +static DEVICE_ATTR(charge_colour, 0220, NULL, razer_attr_write_charge_colour); +static DEVICE_ATTR(charge_low_threshold, 0660, razer_attr_read_charge_low_threshold, razer_attr_write_charge_low_threshold); + +static DEVICE_ATTR(matrix_brightness, 0660, razer_attr_read_matrix_brightness, razer_attr_write_matrix_brightness); +static DEVICE_ATTR(matrix_custom_frame, 0220, NULL, razer_attr_write_matrix_custom_frame); +static DEVICE_ATTR(matrix_effect_none, 0220, NULL, razer_attr_write_matrix_effect_none); +static DEVICE_ATTR(matrix_effect_custom, 0220, NULL, razer_attr_write_matrix_effect_custom); +static DEVICE_ATTR(matrix_effect_static, 0220, NULL, razer_attr_write_matrix_effect_static); +static DEVICE_ATTR(matrix_effect_wave, 0220, NULL, razer_attr_write_matrix_effect_wave); +static DEVICE_ATTR(matrix_effect_spectrum, 0220, NULL, razer_attr_write_matrix_effect_spectrum); +static DEVICE_ATTR(matrix_effect_reactive, 0220, NULL, razer_attr_write_matrix_effect_reactive); +static DEVICE_ATTR(matrix_effect_breath, 0220, NULL, razer_attr_write_matrix_effect_breath); + +static DEVICE_ATTR(scroll_led_brightness, 0660, razer_attr_read_scroll_led_brightness, razer_attr_write_scroll_led_brightness); +// For "extended" matrix effects +static DEVICE_ATTR(scroll_matrix_effect_wave, 0220, NULL, razer_attr_write_scroll_matrix_effect_wave); +static DEVICE_ATTR(scroll_matrix_effect_spectrum, 0220, NULL, razer_attr_write_scroll_matrix_effect_spectrum); +static DEVICE_ATTR(scroll_matrix_effect_reactive, 0220, NULL, razer_attr_write_scroll_matrix_effect_reactive); +static DEVICE_ATTR(scroll_matrix_effect_breath, 0220, NULL, razer_attr_write_scroll_matrix_effect_breath); +static DEVICE_ATTR(scroll_matrix_effect_static, 0220, NULL, razer_attr_write_scroll_matrix_effect_static); +static DEVICE_ATTR(scroll_matrix_effect_blinking, 0220, NULL, razer_attr_write_scroll_matrix_effect_blinking); +static DEVICE_ATTR(scroll_matrix_effect_none, 0220, NULL, razer_attr_write_scroll_matrix_effect_none); +static DEVICE_ATTR(scroll_matrix_effect_on, 0220, NULL, razer_attr_write_scroll_matrix_effect_on); + +static DEVICE_ATTR(logo_led_brightness, 0660, razer_attr_read_logo_led_brightness, razer_attr_write_logo_led_brightness); +// For "extended" matrix effects +static DEVICE_ATTR(logo_matrix_effect_wave, 0220, NULL, razer_attr_write_logo_matrix_effect_wave); +static DEVICE_ATTR(logo_matrix_effect_spectrum, 0220, NULL, razer_attr_write_logo_matrix_effect_spectrum); +static DEVICE_ATTR(logo_matrix_effect_reactive, 0220, NULL, razer_attr_write_logo_matrix_effect_reactive); +static DEVICE_ATTR(logo_matrix_effect_breath, 0220, NULL, razer_attr_write_logo_matrix_effect_breath); +static DEVICE_ATTR(logo_matrix_effect_static, 0220, NULL, razer_attr_write_logo_matrix_effect_static); +static DEVICE_ATTR(logo_matrix_effect_blinking, 0220, NULL, razer_attr_write_logo_matrix_effect_blinking); +static DEVICE_ATTR(logo_matrix_effect_none, 0220, NULL, razer_attr_write_logo_matrix_effect_none); +static DEVICE_ATTR(logo_matrix_effect_on, 0220, NULL, razer_attr_write_logo_matrix_effect_on); + +static DEVICE_ATTR(left_led_brightness, 0660, razer_attr_read_left_led_brightness, razer_attr_write_left_led_brightness); +// For "extended" matrix effects +static DEVICE_ATTR(left_matrix_effect_wave, 0220, NULL, razer_attr_write_left_matrix_effect_wave); +static DEVICE_ATTR(left_matrix_effect_spectrum, 0220, NULL, razer_attr_write_left_matrix_effect_spectrum); +static DEVICE_ATTR(left_matrix_effect_reactive, 0220, NULL, razer_attr_write_left_matrix_effect_reactive); +static DEVICE_ATTR(left_matrix_effect_breath, 0220, NULL, razer_attr_write_left_matrix_effect_breath); +static DEVICE_ATTR(left_matrix_effect_static, 0220, NULL, razer_attr_write_left_matrix_effect_static); +static DEVICE_ATTR(left_matrix_effect_none, 0220, NULL, razer_attr_write_left_matrix_effect_none); + +static DEVICE_ATTR(right_led_brightness, 0660, razer_attr_read_right_led_brightness, razer_attr_write_right_led_brightness); +// For "extended" matrix effects +static DEVICE_ATTR(right_matrix_effect_wave, 0220, NULL, razer_attr_write_right_matrix_effect_wave); +static DEVICE_ATTR(right_matrix_effect_spectrum, 0220, NULL, razer_attr_write_right_matrix_effect_spectrum); +static DEVICE_ATTR(right_matrix_effect_reactive, 0220, NULL, razer_attr_write_right_matrix_effect_reactive); +static DEVICE_ATTR(right_matrix_effect_breath, 0220, NULL, razer_attr_write_right_matrix_effect_breath); +static DEVICE_ATTR(right_matrix_effect_static, 0220, NULL, razer_attr_write_right_matrix_effect_static); +static DEVICE_ATTR(right_matrix_effect_none, 0220, NULL, razer_attr_write_right_matrix_effect_none); + +// For old-school led commands +// matrix_brightness should mostly be called backlight_led_brightness (but it's too much work now for old devices) +static DEVICE_ATTR(backlight_led_brightness, 0660, razer_attr_read_backlight_led_brightness, razer_attr_write_backlight_led_brightness); +// For "extended" matrix effects +static DEVICE_ATTR(backlight_matrix_effect_wave, 0220, NULL, razer_attr_write_backlight_matrix_effect_wave); +static DEVICE_ATTR(backlight_matrix_effect_spectrum, 0220, NULL, razer_attr_write_backlight_matrix_effect_spectrum); +static DEVICE_ATTR(backlight_matrix_effect_reactive, 0220, NULL, razer_attr_write_backlight_matrix_effect_reactive); +static DEVICE_ATTR(backlight_matrix_effect_breath, 0220, NULL, razer_attr_write_backlight_matrix_effect_breath); +static DEVICE_ATTR(backlight_matrix_effect_static, 0220, NULL, razer_attr_write_backlight_matrix_effect_static); +static DEVICE_ATTR(backlight_matrix_effect_none, 0220, NULL, razer_attr_write_backlight_matrix_effect_none); +static DEVICE_ATTR(backlight_matrix_effect_on, 0220, NULL, razer_attr_write_backlight_matrix_effect_on); + +// For HyperPolling Wireless Dongle +static DEVICE_ATTR(hyperpolling_wireless_dongle_indicator_led_mode, 0220, NULL, razer_attr_write_hyperpolling_wireless_dongle_indicator_led_mode); +static DEVICE_ATTR(hyperpolling_wireless_dongle_pair, 0220, NULL, razer_attr_write_hyperpolling_wireless_dongle_pair); +static DEVICE_ATTR(hyperpolling_wireless_dongle_unpair, 0220, NULL, razer_attr_write_hyperpolling_wireless_dongle_unpair); + +#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 + +/* + * Documentation: https://www.kernel.org/doc/html/latest/input/event-codes.html#ev-rel + * See also https://github.com/torvalds/linux/blob/v5.14/drivers/hid/hid-input.c#L1298-L1303 + */ +#define SCROLL_DETENT 120 + +/** + * 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 + */ +static 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 + */ +static 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 + */ +static 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_report_rel(dev->input, REL_HWHEEL_HI_RES, dev->hwheel_value * SCROLL_DETENT); + 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_report_rel(rdev->input, REL_HWHEEL_HI_RES, rel_value * SCROLL_DETENT); + 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 + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) +static int dev_is_on_bus(struct device *dev, const void *data) +#else +static int dev_is_on_bus(struct device *dev, void *data) +#endif +{ + const struct bus_type *bus = data; + return dev->bus == bus; +} + +/** + * Find an interface on a usb_device with the specified protocol + */ +static struct usb_interface *find_intf_with_proto(struct usb_device *usbdev, u8 proto) +{ + int i; + + for (i = 0; i < usbdev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *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) +{ + const struct bus_type *mouse_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, (void *)mouse_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 + */ +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_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + /* 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]; + } + + /* 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; + + if (!m_rdev) { + printk(KERN_WARNING "razermouse: Couldn't find mouse intf from kbd intf\n"); + return 1; + } + + 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) + + while(--index > 0) { + u8 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[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; +} + +/** + * 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: + case USB_DEVICE_ID_RAZER_BASILISK_V3: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + /* Linux HID doesn't detect the Basilisk V2's tilt wheel + * or buttons beyond the first 5 */ + 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); + fallthrough; + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_NAGA_2014: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + input_set_capability(hidinput->input, EV_REL, REL_HWHEEL); + input_set_capability(hidinput->input, EV_REL, REL_HWHEEL_HI_RES); + input_set_capability(hidinput->input, EV_KEY, BTN_FORWARD); + input_set_capability(hidinput->input, EV_KEY, BTN_BACK); + break; + } + } + + return 0; +} + +/** + * Mouse init function + */ +static void razer_mouse_init(struct razer_mouse_device *dev, struct usb_interface *intf, struct hid_device *hdev) +{ + struct usb_device *usb_dev = interface_to_usbdev(intf); + unsigned int rand_serial = 0; + + // Initialise mutex + mutex_init(&dev->lock); + // Setup values + dev->usb_dev = usb_dev; + dev->usb_vid = usb_dev->descriptor.idVendor; + dev->usb_pid = usb_dev->descriptor.idProduct; + dev->usb_interface_protocol = intf->cur_altsetting->desc.bInterfaceProtocol; + dev->usb_interface_subclass = intf->cur_altsetting->desc.bInterfaceSubClass; + + // Get a "random" integer + get_random_bytes(&rand_serial, sizeof(unsigned int)); + sprintf(&dev->serial[0], "PM%012u", rand_serial); + + // Setup orochi2011 + dev->orochi2011.dpi = 0x4c; + dev->orochi2011.poll = 500; + + // Setup default values for DeathAdder 3.5G + dev->da3_5g.leds = 3; // Lights up all lights + 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 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0) + hrtimer_setup(&dev->repeat_timer, wheel_tilt_repeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +#else + hrtimer_init(&dev->repeat_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + dev->repeat_timer.function = wheel_tilt_repeat; +#endif + dev->tilt_hwheel = 1; + dev->tilt_repeat_delay = 250; + dev->tilt_repeat = 33; +} + +/** + * Probe method is ran whenever a device is binded to the driver + */ +static int razer_mouse_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int retval = 0; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct razer_mouse_device *dev = NULL; + unsigned char expected_subclass = 0xFF; + + dev = kzalloc(sizeof(struct razer_mouse_device), GFP_KERNEL); + + if(dev == NULL) { + dev_err(&intf->dev, "out of memory\n"); + return -ENOMEM; + } + + // Init data + razer_mouse_init(dev, intf, hdev); + + switch(dev->usb_pid) { + 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: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + expected_subclass = 0x01; + break; + } + + if(dev->usb_interface_protocol == USB_INTERFACE_PROTOCOL_MOUSE + && (expected_subclass == 0xFF || dev->usb_interface_subclass == expected_subclass)) { + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_version); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_test); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_firmware_version); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_type); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_serial); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_mode); + + switch(dev->usb_pid) { + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + fallthrough; + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + 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); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + 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); + fallthrough; + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); + fallthrough; + case USB_DEVICE_ID_RAZER_BASILISK_V3: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_mode); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_acceleration); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_smart_reel); + 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); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_mode); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_acceleration); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_smart_reel); + 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); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + 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); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + break; + + case USB_DEVICE_ID_RAZER_IMPERATOR: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_OUROBOROS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_blinking); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_blinking); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2013: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_TAIPAN: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_NAGA_2014: + 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); + fallthrough; + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_2012: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_on); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_blinking); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_blinking); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_blinking); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_blinking); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + break; + + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_on); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_left_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_right_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + + 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); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_effect); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + fallthrough; + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_indicator_led_mode); + fallthrough; + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_indicator_led_mode); + fallthrough; + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_indicator_led_mode); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_pair); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_unpair); + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_custom); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_COBRA: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + break; + + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_led_brightness); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + break; + + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_poll_rate); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_dpi_stages); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_level); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_status); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_charge_low_threshold); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_device_idle_time); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_spectrum); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_wave); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_static); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_effect_none); + CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_matrix_brightness); + break; + } + + } + + hid_set_drvdata(hdev, dev); + dev_set_drvdata(&hdev->dev, dev); + + retval = hid_parse(hdev); + if(retval) { + hid_err(hdev, "parse failed\n"); + goto exit_free; + } + retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (retval) { + hid_err(hdev, "hw start failed\n"); + goto exit_free; + } + + //razer_reset(usb_dev); + //razer_activate_macro_keys(usb_dev); + //msleep(3000); + return 0; + +exit_free: + kfree(dev); + return retval; +} + +/** + * Unbind function + */ +static void razer_mouse_disconnect(struct hid_device *hdev) +{ + struct razer_mouse_device *dev; + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + + dev = hid_get_drvdata(hdev); + + if(intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) { + device_remove_file(&hdev->dev, &dev_attr_version); + device_remove_file(&hdev->dev, &dev_attr_test); + device_remove_file(&hdev->dev, &dev_attr_firmware_version); + device_remove_file(&hdev->dev, &dev_attr_device_type); + device_remove_file(&hdev->dev, &dev_attr_device_serial); + device_remove_file(&hdev->dev, &dev_attr_device_mode); + + switch(usb_dev->descriptor.idProduct) { + case USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION: + case USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + device_remove_file(&hdev->dev, &dev_attr_charge_effect); + device_remove_file(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + fallthrough; + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_left_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_right_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + device_remove_file(&hdev->dev, &dev_attr_charge_effect); + device_remove_file(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + 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); + device_remove_file(&hdev->dev, &dev_attr_left_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_right_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + 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); + fallthrough; + case USB_DEVICE_ID_RAZER_DEATHADDER_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_35K: + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); + fallthrough; + case USB_DEVICE_ID_RAZER_BASILISK_V3: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_scroll_mode); + device_remove_file(&hdev->dev, &dev_attr_scroll_acceleration); + device_remove_file(&hdev->dev, &dev_attr_scroll_smart_reel); + 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); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_scroll_mode); + device_remove_file(&hdev->dev, &dev_attr_scroll_acceleration); + device_remove_file(&hdev->dev, &dev_attr_scroll_smart_reel); + 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); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_backlight_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + 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); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_backlight_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS: + case USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED: + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_charge_effect); + device_remove_file(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_MAMBA_WIRED: + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED: + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + device_remove_file(&hdev->dev, &dev_attr_backlight_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS: + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + break; + + case USB_DEVICE_ID_RAZER_IMPERATOR: + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_OUROBOROS: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2013: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_blinking); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_blinking); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_2013: + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX: + case USB_DEVICE_ID_RAZER_NAGA_HEX_RED: + case USB_DEVICE_ID_RAZER_TAIPAN: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_NAGA_2014: + 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); + fallthrough; + case USB_DEVICE_ID_RAZER_NAGA: + case USB_DEVICE_ID_RAZER_NAGA_2012: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_on); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_backlight_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_blinking); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_blinking); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_3500: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_blinking); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_blinking); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_2000: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + break; + + case USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA: + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + device_remove_file(&hdev->dev, &dev_attr_backlight_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_backlight_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_1800: + case USB_DEVICE_ID_RAZER_DEATHADDER_1800: + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_ABYSSUS_2000: + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_on); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + break; + + case USB_DEVICE_ID_RAZER_NAGA_X: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_left_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_right_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_charge_effect); + device_remove_file(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_charge_effect); + device_remove_file(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_left_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_left_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_right_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_right_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + + 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); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER: + device_remove_file(&hdev->dev, &dev_attr_charge_effect); + device_remove_file(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED: + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_charge_effect); + device_remove_file(&hdev->dev, &dev_attr_charge_colour); + fallthrough; + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + fallthrough; + case USB_DEVICE_ID_RAZER_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_indicator_led_mode); + fallthrough; + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER: + case USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH: + case USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER: + case USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER: + case USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED: + case USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS: + device_remove_file(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_indicator_led_mode); + fallthrough; + case USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_indicator_led_mode); + device_remove_file(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_pair); + device_remove_file(&hdev->dev, &dev_attr_hyperpolling_wireless_dongle_unpair); + break; + + case USB_DEVICE_ID_RAZER_VIPER_8K: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_custom); + device_remove_file(&hdev->dev, &dev_attr_matrix_custom_frame); + break; + + case USB_DEVICE_ID_RAZER_COBRA: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + + device_remove_file(&hdev->dev, &dev_attr_logo_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_logo_matrix_effect_breath); + break; + + case USB_DEVICE_ID_RAZER_DEATHADDER_V3: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + break; + + case USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_reactive); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_breath); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + break; + + case USB_DEVICE_ID_RAZER_NAGA_EPIC: + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_scroll_led_brightness); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_scroll_matrix_effect_spectrum); + break; + + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS: + case USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED: + device_remove_file(&hdev->dev, &dev_attr_poll_rate); + device_remove_file(&hdev->dev, &dev_attr_dpi); + device_remove_file(&hdev->dev, &dev_attr_dpi_stages); + device_remove_file(&hdev->dev, &dev_attr_charge_level); + device_remove_file(&hdev->dev, &dev_attr_charge_status); + device_remove_file(&hdev->dev, &dev_attr_charge_low_threshold); + device_remove_file(&hdev->dev, &dev_attr_device_idle_time); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_spectrum); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_wave); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_static); + device_remove_file(&hdev->dev, &dev_attr_matrix_effect_none); + device_remove_file(&hdev->dev, &dev_attr_matrix_brightness); + break; + } + + } + + hid_hw_stop(hdev); + hrtimer_cancel(&dev->repeat_timer); + + kfree(dev); + dev_info(&intf->dev, "Razer Device disconnected\n"); +} + +/** + * Device ID mapping table + */ +static const struct hid_device_id razer_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_OROCHI_2011) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ABYSSUS_1800) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ABYSSUS_2000) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_3_5G) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_HEX_RED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_2012) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_2014) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_HEX) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ABYSSUS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_TAIPAN) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_IMPERATOR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_OUROBOROS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_2013) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_OROCHI_2013) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_OROCHI_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_HEX_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_ELITE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ABYSSUS_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_3500) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_TRINITY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_ELITE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_1800) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_MINI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS) }, + { 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_ESSENTIAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V3) }, + { 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) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_2000) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_X_HYPERSPEED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_X) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_8K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V3_35K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_COBRA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_NAGA_EPIC) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(hid, razer_devices); + +/** + * Describes the contents of the driver + */ +static struct hid_driver razer_mouse_driver = { + .name = "razermouse", + .id_table = razer_devices, + .probe = razer_mouse_probe, + .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/openrazer/driver/razermouse_driver.h b/openrazer/driver/razermouse_driver.h new file mode 100644 index 00000000..fd45d99e --- /dev/null +++ b/openrazer/driver/razermouse_driver.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2015 Terri Cain + */ + +#ifndef __HID_RAZER_MOUSE_H +#define __HID_RAZER_MOUSE_H + +#define USB_DEVICE_ID_RAZER_OROCHI_2011 0x0013 +#define USB_DEVICE_ID_RAZER_NAGA 0x0015 +#define USB_DEVICE_ID_RAZER_DEATHADDER_3_5G 0x0016 +#define USB_DEVICE_ID_RAZER_NAGA_EPIC 0x001F +#define USB_DEVICE_ID_RAZER_ABYSSUS_1800 0x0020 +#define USB_DEVICE_ID_RAZER_MAMBA_2012_WIRED 0x0024 +#define USB_DEVICE_ID_RAZER_MAMBA_2012_WIRELESS 0x0025 +#define USB_DEVICE_ID_RAZER_DEATHADDER_3_5G_BLACK 0x0029 +#define USB_DEVICE_ID_RAZER_NAGA_2012 0x002E +#define USB_DEVICE_ID_RAZER_IMPERATOR 0x002F +#define USB_DEVICE_ID_RAZER_OUROBOROS 0x0032 +#define USB_DEVICE_ID_RAZER_TAIPAN 0x0034 +#define USB_DEVICE_ID_RAZER_NAGA_HEX_RED 0x0036 +#define USB_DEVICE_ID_RAZER_DEATHADDER_2013 0x0037 +#define USB_DEVICE_ID_RAZER_DEATHADDER_1800 0x0038 +#define USB_DEVICE_ID_RAZER_OROCHI_2013 0x0039 +#define USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA 0x003E +#define USB_DEVICE_ID_RAZER_NAGA_EPIC_CHROMA_DOCK 0x003F +#define USB_DEVICE_ID_RAZER_NAGA_2014 0x0040 +#define USB_DEVICE_ID_RAZER_NAGA_HEX 0x0041 +#define USB_DEVICE_ID_RAZER_ABYSSUS 0x0042 +#define USB_DEVICE_ID_RAZER_DEATHADDER_CHROMA 0x0043 +#define USB_DEVICE_ID_RAZER_MAMBA_WIRED 0x0044 +#define USB_DEVICE_ID_RAZER_MAMBA_WIRELESS 0x0045 +#define USB_DEVICE_ID_RAZER_MAMBA_TE_WIRED 0x0046 +#define USB_DEVICE_ID_RAZER_OROCHI_CHROMA 0x0048 +#define USB_DEVICE_ID_RAZER_DIAMONDBACK_CHROMA 0x004C +#define USB_DEVICE_ID_RAZER_DEATHADDER_2000 0x004F +#define USB_DEVICE_ID_RAZER_NAGA_HEX_V2 0x0050 +#define USB_DEVICE_ID_RAZER_NAGA_CHROMA 0x0053 +#define USB_DEVICE_ID_RAZER_DEATHADDER_3500 0x0054 +#define USB_DEVICE_ID_RAZER_LANCEHEAD_WIRED 0x0059 +#define USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS 0x005A +#define USB_DEVICE_ID_RAZER_ABYSSUS_V2 0x005B +#define USB_DEVICE_ID_RAZER_DEATHADDER_ELITE 0x005C +#define USB_DEVICE_ID_RAZER_ABYSSUS_2000 0x005E +#define USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED 0x0060 +#define USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER 0x0062 +#define USB_DEVICE_ID_RAZER_BASILISK 0x0064 +#define USB_DEVICE_ID_RAZER_BASILISK_ESSENTIAL 0x0065 +#define USB_DEVICE_ID_RAZER_NAGA_TRINITY 0x0067 +#define USB_DEVICE_ID_RAZER_ABYSSUS_ELITE_DVA_EDITION 0x006A +#define USB_DEVICE_ID_RAZER_ABYSSUS_ESSENTIAL 0x006B +#define USB_DEVICE_ID_RAZER_MAMBA_ELITE 0x006C +#define USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL 0x006E +#define USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER 0x006F +#define USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED 0x0070 +#define USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_WHITE_EDITION 0x0071 +#define USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_RECEIVER 0x0072 +#define USB_DEVICE_ID_RAZER_MAMBA_WIRELESS_WIRED 0x0073 +#define USB_DEVICE_ID_RAZER_PRO_CLICK_RECEIVER 0x0077 +#define USB_DEVICE_ID_RAZER_VIPER 0x0078 +#define USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED 0x007A +#define USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS 0x007B +#define USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED 0x007C +#define USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS 0x007D +#define USB_DEVICE_ID_RAZER_PRO_CLICK_WIRED 0x0080 +#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_BASILISK_ULTIMATE_WIRED 0x0086 +#define USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER 0x0088 +#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 +#define USB_DEVICE_ID_RAZER_NAGA_PRO_WIRED 0x008F +#define USB_DEVICE_ID_RAZER_NAGA_PRO_WIRELESS 0x0090 +#define USB_DEVICE_ID_RAZER_VIPER_8K 0x0091 +#define USB_DEVICE_ID_RAZER_OROCHI_V2_RECEIVER 0x0094 +#define USB_DEVICE_ID_RAZER_OROCHI_V2_BLUETOOTH 0x0095 +#define USB_DEVICE_ID_RAZER_NAGA_X 0x0096 +#define USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL_2021 0x0098 +#define USB_DEVICE_ID_RAZER_BASILISK_V3 0x0099 +#define USB_DEVICE_ID_RAZER_PRO_CLICK_MINI_RECEIVER 0x009A +#define USB_DEVICE_ID_RAZER_DEATHADDER_V2_X_HYPERSPEED 0x009C +#define USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRED 0x009E +#define USB_DEVICE_ID_RAZER_VIPER_MINI_SE_WIRELESS 0x009F +#define USB_DEVICE_ID_RAZER_DEATHADDER_V2_LITE 0x00A1 +#define USB_DEVICE_ID_RAZER_COBRA 0x00A3 +#define USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRED 0x00A5 +#define USB_DEVICE_ID_RAZER_VIPER_V2_PRO_WIRELESS 0x00A6 +#define USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRED 0x00A7 +#define USB_DEVICE_ID_RAZER_NAGA_V2_PRO_WIRELESS 0x00A8 +#define USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRED 0x00AA +#define USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_WIRELESS 0x00AB +#define USB_DEVICE_ID_RAZER_COBRA_PRO_WIRED 0x00AF +#define USB_DEVICE_ID_RAZER_COBRA_PRO_WIRELESS 0x00B0 +#define USB_DEVICE_ID_RAZER_DEATHADDER_V3 0x00B2 +#define USB_DEVICE_ID_RAZER_HYPERPOLLING_WIRELESS_DONGLE 0x00B3 +#define USB_DEVICE_ID_RAZER_NAGA_V2_HYPERSPEED_RECEIVER 0x00B4 +#define USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED 0x00B6 +#define USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS 0x00B7 +#define USB_DEVICE_ID_RAZER_VIPER_V3_HYPERSPEED 0x00B8 +#define USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED 0x00B9 +#define USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRED 0x00C0 +#define USB_DEVICE_ID_RAZER_VIPER_V3_PRO_WIRELESS 0x00C1 +#define USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRED_ALT 0x00C2 +#define USB_DEVICE_ID_RAZER_DEATHADDER_V3_PRO_WIRELESS_ALT 0x00C3 +#define USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRED 0x00C4 +#define USB_DEVICE_ID_RAZER_DEATHADDER_V3_HYPERSPEED_WIRELESS 0x00C5 +#define USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRED 0x00C7 +#define USB_DEVICE_ID_RAZER_PRO_CLICK_V2_VERTICAL_EDITION_WIRELESS 0x00C8 +#define USB_DEVICE_ID_RAZER_BASILISK_V3_35K 0x00CB +#define USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRED 0x00CC +#define USB_DEVICE_ID_RAZER_BASILISK_V3_PRO_35K_WIRELESS 0x00CD +#define USB_DEVICE_ID_RAZER_BASILISK_V3 0x0099 +#define USB_DEVICE_ID_RAZER_BASILISK_V3_X_HYPERSPEED 0x00B9 + + +/* Each keyboard report has 90 bytes*/ +#define RAZER_REPORT_LEN 0x5A + +#define RAZER_MAMBA_ROW_LEN 15 // 0 => 14 +#define RAZER_MAMBA_TE_ROW_LEN 16 // 0 => 15 +#define RAZER_DIAMONDBACK_ROW_LEN 21 // 0 => 20 + +#define RAZER_MOUSE_WAIT_MIN_US 600 +#define RAZER_MOUSE_WAIT_MAX_US 800 + +#define RAZER_NEW_MOUSE_RECEIVER_WAIT_MIN_US 31000 +#define RAZER_NEW_MOUSE_RECEIVER_WAIT_MAX_US 31100 + +#define RAZER_ATHERIS_RECEIVER_WAIT_MIN_US 400000 +#define RAZER_ATHERIS_RECEIVER_WAIT_MAX_US 400100 + +#define RAZER_VIPER_MOUSE_RECEIVER_WAIT_MIN_US 59900 +#define RAZER_VIPER_MOUSE_RECEIVER_WAIT_MAX_US 60000 + +#define RAZER_MOUSE_MAX_DPI_STAGES 5 + +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; + + unsigned short usb_vid; + unsigned short usb_pid; + + char serial[23]; // Now storing a random serial to be used with old devices that don't support it + + struct { + unsigned char led; + unsigned char dpi; + unsigned short poll; + } orochi2011; + + // The DeathAdder 3.5G, uses OR logic so need to remember last values. Part of a 4byte payload + struct { + unsigned char poll; + unsigned char dpi; + unsigned char profile; + unsigned char leds; + } da3_5g; +}; + +// Mamba Key Location +// 0 => 6 ---> top left => bottom left +// 7 => 13 ---> top right => bottom right +// 14 ---> Scroll LED + +// Mamba TE Key Location +// 0 => 6 ---> top left => bottom left +// 7 => 13 ---> top right => bottom right +// 14 ---> Logo LED +// 15 ---> Scroll LED + +#endif \ No newline at end of file diff --git a/openrazer/driver/usb_hid_keys.h b/openrazer/driver/usb_hid_keys.h new file mode 100644 index 00000000..a5fbb68e --- /dev/null +++ b/openrazer/driver/usb_hid_keys.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * USB HID keycodes + * http://www.freebsddiary.org/APC/usb_hid_usages.php + */ + +#ifndef __USB_HID_KEYS_H +#define __USB_HID_KEYS_H + +#define USB_HID_KEY_F13 0x68 +#define USB_HID_KEY_F14 0x69 +#define USB_HID_KEY_F15 0x6A +#define USB_HID_KEY_F16 0x6B +#define USB_HID_KEY_F17 0x6C +#define USB_HID_KEY_F18 0x6D +#define USB_HID_KEY_F19 0x6E +#define USB_HID_KEY_F20 0x6F +#define USB_HID_KEY_F21 0x70 +#define USB_HID_KEY_F22 0x71 +#define USB_HID_KEY_F23 0x72 +#define USB_HID_KEY_F24 0x73 + +#define USB_HID_KEY_MEDIA_PLAYPAUSE 0xE8 +#define USB_HID_KEY_MEDIA_PREVIOUSSONG 0xEA +#define USB_HID_KEY_MEDIA_NEXTSONG 0xEB +#define USB_HID_KEY_MEDIA_VOLUMEUP 0xED +#define USB_HID_KEY_MEDIA_VOLUMEDOWN 0xEE +#define USB_HID_KEY_MEDIA_MUTE 0xEF +#define USB_HID_KEY_MEDIA_SLEEP 0xF8 + +// https://usb.org/sites/default/files/hut1_22.pdf +#define USB_HID_USAGE_MEDIA_PLAYPAUSE 0xCD +#define USB_HID_USAGE_MEDIA_PREVIOUSSONG 0xB6 +#define USB_HID_USAGE_MEDIA_NEXTSONG 0xB5 +#define USB_HID_USAGE_MEDIA_VOLUMEUP 0xE9 +#define USB_HID_USAGE_MEDIA_VOLUMEDOWN 0xEA +#define USB_HID_USAGE_MEDIA_MUTE 0xE2 + +#endif // __USB_HID_KEYS_H diff --git a/openrazer/examples/advanced_effect.py b/openrazer/examples/advanced_effect.py new file mode 100644 index 00000000..e1d672c7 --- /dev/null +++ b/openrazer/examples/advanced_effect.py @@ -0,0 +1,87 @@ +import colorsys +import random + +from openrazer.client import DeviceManager +from openrazer.client import constants as razer_constants + +# Create a DeviceManager. This is used to get specific devices +device_manager = DeviceManager() + + +print("Found {} Razer devices".format(len(device_manager.devices))) +print() + +# Disable daemon effect syncing. +# Without this, the daemon will try to set the lighting effect to every device. +device_manager.sync_effects = False + +# List of effect I've chosen to make an example for +effects = [ + 'breath_random', + 'breath_single', + 'breath_dual', + 'breath_triple', + 'reactive', + 'spectrum', + 'static', + 'wave', +] + +# Helper function to generate interesting colors + + +def random_color(): + rgb = colorsys.hsv_to_rgb(random.uniform(0, 1), random.uniform(0.5, 1), 1) + return tuple(map(lambda x: int(256 * x), rgb)) + + +# Iterate over each device and set a random effect that it supports. +for device in device_manager.devices: + # Check which effect this device supports. + device_effects = [effect for effect in effects if device.fx.has(effect)] + # print("{} supports {}".format(device.name, device_effects)) + + if len(device_effects) == 0: + print("Device {} doesn't support any of the effects".format(device.name)) + continue + effect = random.choice(device_effects) + print("Setting {} to effect {}".format(device.name, effect)) + + # Ad an example for each effect + if effect == 'breath_random': + device.fx.breath_random() + + elif effect == 'breath_single': + color = random_color() + device.fx.breath_single(color[0], color[1], color[2]) + + elif effect == 'breath_dual': + color = random_color() + color2 = random_color() + device.fx.breath_dual(color[0], color[1], color[2], + color2[0], color2[1], color2[2]) + + elif effect == 'breath_triple': + color = random_color() + color2 = random_color() + color3 = random_color() + device.fx.breath_triple(color[0], color[1], color[2], + color2[0], color2[1], color2[2], + color3[0], color3[1], color3[2]) + + elif effect == 'reactive': + color = random_color() + times = [razer_constants.REACTIVE_500MS, razer_constants.REACTIVE_1000MS, + razer_constants.REACTIVE_1500MS, razer_constants.REACTIVE_2000MS] + device.fx.reactive(color[0], color[1], color[2], random.choice(times)) + + elif effect == 'spectrum': + device.fx.spectrum() + + elif effect == 'static': + color = random_color() + device.fx.static(*color) + + elif effect == 'wave': + directions = [razer_constants.WAVE_LEFT, razer_constants.WAVE_RIGHT] + device.fx.wave(random.choice(directions)) diff --git a/openrazer/examples/basic_effect.py b/openrazer/examples/basic_effect.py new file mode 100644 index 00000000..0b00c797 --- /dev/null +++ b/openrazer/examples/basic_effect.py @@ -0,0 +1,21 @@ +from openrazer.client import DeviceManager +from openrazer.client import constants as razer_constants + +# Create a DeviceManager. This is used to get specific devices +device_manager = DeviceManager() + + +print("Found {} Razer devices".format(len(device_manager.devices))) +print() + +# Disable daemon effect syncing. +# Without this, the daemon will try to set the lighting effect to every device. +device_manager.sync_effects = False + +# Iterate over each device and set the wave effect +for device in device_manager.devices: + print("Setting {} to wave".format(device.name)) + + # Set the effect to wave. + # wave requires a direction, but different effect have different arguments. + device.fx.wave(razer_constants.WAVE_LEFT) diff --git a/openrazer/examples/change_on_screensaver.py b/openrazer/examples/change_on_screensaver.py new file mode 100755 index 00000000..b8ecc72b --- /dev/null +++ b/openrazer/examples/change_on_screensaver.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +# +# References: +# https://github.com/openrazer/openrazer/blob/master/daemon/openrazer_daemon/misc/screensaver_monitor.py +# https://stackoverflow.com/questions/37320352/receive-dbus-signals-with-python +# +# [!] Make sure this key is set in ~/.config/openrazer/razer.conf: +# devices_off_on_screensaver = False +# + +import dbus +import openrazer.client +from gi.repository import GLib +from dbus.mainloop.glib import DBusGMainLoop + +DBUS_SCREENSAVER_INTERFACES = ( + 'org.cinnamon.ScreenSaver', + 'org.freedesktop.ScreenSaver', + 'org.gnome.ScreenSaver', + 'org.mate.ScreenSaver', + 'org.xfce.ScreenSaver', +) + + +def signal_callback(active): + if active: + print("Lock screen/screensaver activated") + # Set to red + device.fx.static(255, 0, 0) + else: + print("Lock screen/screensaver deactivated") + # Set to green + device.fx.static(0, 255, 0) + + +DBusGMainLoop(set_as_default=True) +bus = dbus.SessionBus() + +# Register screensaver signals +for bus_name in DBUS_SCREENSAVER_INTERFACES: + bus.add_signal_receiver(signal_callback, dbus_interface=bus_name, signal_name='ActiveChanged') + +# Select the first device and sync effect to all devices +devman = openrazer.client.DeviceManager() +devman.sync_effects = True +device = devman.devices[0] + +# Press CTRL+C to interrupt +loop = GLib.MainLoop() +loop.run() diff --git a/openrazer/examples/cpu_temperature.py b/openrazer/examples/cpu_temperature.py new file mode 100644 index 00000000..52ae6b64 --- /dev/null +++ b/openrazer/examples/cpu_temperature.py @@ -0,0 +1,69 @@ +""" +Example of changing the colour of all Razer devices based on the CPU +temperature +""" +import colorsys +import time + +import openrazer.client + +# These settings are nice if your CPU temperature is a bit less than 30°C +# at idle and a bit more than 60°C at full load, tune them for your needs +tGreen = 30 +tRed = 60 + +tRange = 3 * (tRed - tGreen) +colour0 = tRed / tRange +tRange = 1000 * tRange + +devman = openrazer.client.DeviceManager() +devman.sync_effects = False +devices = devman.devices + +if not devices: + print("No devices connected") + exit(1) + +lastTemp = 0 + +while True: + # For my computer it's hwmon2/temp1_input but it may be different for you + # cat /sys/class/hwmon/hwmonX/tempY_input can help you (with X between 0 + # and 2 and Y between 0 and 12, the result is in millidegrees). + # you will need lm-sensors for this to work. + with open("/sys/class/hwmon/hwmon2/temp1_input", "r") as f: + temp = f.readline() + + shortTemp = temp[:2] + + # Now we can change the colour each time temperature changes + if shortTemp != lastTemp: + # We convert the temperature (millidegrees) to the hue + # (HSV, hue between 0 and 1) + hue = (colour0 - float(temp) / tRange) % 1 + + # The colours list RGB with R,G,B between 0 and 1 + colour = colorsys.hsv_to_rgb(hue, 1, 1) + + # Needs to be an integer (0-255, e.g. 1 == 255) + colour = list(map(lambda x: (int(255 * x)), colour)) + + # Set effect on device + for device in devices: + # A device may have multiple zones + if device.has("lighting_static"): + device.fx.static(colour[0], colour[1], colour[2]) + if device.has("lighting_backlight"): + device.fx.misc.backlight.static(colour[0], colour[1], colour[2]) + if device.has("lighting_logo_static"): + device.fx.misc.logo.static(colour[0], colour[1], colour[2]) + if device.has("lighting_scroll_static"): + device.fx.misc.scroll_wheel.static(colour[0], colour[1], colour[2]) + if device.has("lighting_left_static"): + device.fx.misc.left.static(colour[0], colour[1], colour[2]) + if device.has("lighting_right_static"): + device.fx.misc.right.static(colour[0], colour[1], colour[2]) + + lastTemp = shortTemp + + time.sleep(1) diff --git a/openrazer/examples/custom_starlight.py b/openrazer/examples/custom_starlight.py new file mode 100644 index 00000000..5033d14e --- /dev/null +++ b/openrazer/examples/custom_starlight.py @@ -0,0 +1,109 @@ +from collections import defaultdict +import colorsys +import random +import sys +import time +import threading + +from openrazer.client import DeviceManager +from openrazer.client import constants as razer_constants + +# Set a quit flag that will be used when the user quits to restore effects. +quit = False + +# Create a DeviceManager. This is used to get specific devices +device_manager = DeviceManager() + + +print("Found {} Razer devices".format(len(device_manager.devices))) + +devices = device_manager.devices +for device in list(devices): + if not device.fx.advanced: + print("Skipping device " + device.name + " (" + device.serial + ")") + devices.remove(device) + +print() + +# Disable daemon effect syncing. +# Without this, the daemon will try to set the lighting effect to every device. +device_manager.sync_effects = False + +# Helper function to generate interesting colors + + +def random_color(): + rgb = colorsys.hsv_to_rgb(random.uniform(0, 1), random.uniform(0.5, 1), 1) + return tuple(map(lambda x: int(256 * x), rgb)) + + +# Handle the startlight effect for a single key +def starlight_key(device, row, col, active): + color = random_color() + + hue = random.uniform(0, 1) + start_time = time.time() + + fade_time = 2 + + elapsed = 0 + while elapsed < fade_time: + value = 1 - elapsed / fade_time + rgb = colorsys.hsv_to_rgb(hue, 1, value) + color = tuple(map(lambda x: int(256 * x), rgb)) + + device.fx.advanced.matrix[row, col] = color + + # print(device, color) + time.sleep(1 / 60) + elapsed = time.time() - start_time + + device.fx.advanced.matrix[row, col] = (0, 0, 0) + active[(row, col)] = False + + +# Handle the startlight effect for an entire device +def starlight_effect(device): + rows, cols = device.fx.advanced.rows, device.fx.advanced.cols + active = defaultdict(bool) + + device.fx.advanced.matrix.reset() + device.fx.advanced.draw() + + while True: + row, col = random.randrange(rows), random.randrange(cols) + + if not active[(row, col)]: + active[(row, col)] = True + threading.Thread(target=starlight_key, args=(device, row, col, active)).start() + + time.sleep(0.1) + + if quit: + break + + device.fx.advanced.restore() + + +# Spawn a manager thread for each device and wait on all of them. +threads = [] +for device in devices: + print("Starting starlight for device " + device.name + " (" + device.serial + ")") + t = threading.Thread(target=starlight_effect, args=(device,), daemon=True) + t.start() + threads.append(t) + + +# If there are still threads, update each device. +try: + while any(t.is_alive() for t in threads): + for device in devices: + device.fx.advanced.draw() + time.sleep(1 / 60) +except KeyboardInterrupt: + quit = True + + for t in threads: + t.join() + + sys.exit(0) diff --git a/openrazer/examples/custom_zones.py b/openrazer/examples/custom_zones.py new file mode 100644 index 00000000..bd1719a3 --- /dev/null +++ b/openrazer/examples/custom_zones.py @@ -0,0 +1,42 @@ +import colorsys +import random + +from openrazer.client import DeviceManager +from openrazer.client import constants as razer_constants + +# Create a DeviceManager. This is used to get specific devices +device_manager = DeviceManager() + + +print("Found {} Razer devices".format(len(device_manager.devices))) + +devices = device_manager.devices +for device in list(devices): + if not device.fx.advanced: + print("Skipping device " + device.name + " (" + device.serial + ")") + devices.remove(device) + +print() + +# Disable daemon effect syncing. +# Without this, the daemon will try to set the lighting effect to every device. +device_manager.sync_effects = False + +# Helper function to generate interesting colors + + +def random_color(): + rgb = colorsys.hsv_to_rgb(random.uniform(0, 1), random.uniform(0.5, 1), 1) + return tuple(map(lambda x: int(256 * x), rgb)) + + +# Set random colors for each zone of each device +for device in devices: + print("Drawing to device " + device.name + " (" + device.serial + ")") + rows, cols = device.fx.advanced.rows, device.fx.advanced.cols + + for row in range(rows): + for col in range(cols): + device.fx.advanced.matrix[row, col] = random_color() + + device.fx.advanced.draw() diff --git a/openrazer/examples/dock_chroma_battery_daemon.py b/openrazer/examples/dock_chroma_battery_daemon.py new file mode 100644 index 00000000..14ec0d18 --- /dev/null +++ b/openrazer/examples/dock_chroma_battery_daemon.py @@ -0,0 +1,134 @@ +#!/usr/bin/python3 +# Copyright 2025 Urufusan. +# SPDX-License-Identifier: GPL-2.0-or-later + +# * This example is a daemon that displays the current battery percentage of your mouse with the status LED on a Razer Mouse Dock Chroma +# * https://www.razer.com/gaming-mice-accessories/razer-mouse-dock-chroma + +import os +import time +from typing import Sequence + +import openrazer.client +from openrazer.client.devices import RazerDevice + + +def hex_to_rgb(hex_string: str) -> tuple[int, int, int]: + hex_string = hex_string.lstrip("#") + _r_hex = hex_string[0:2] + _g_hex = hex_string[2:4] + _b_hex = hex_string[4:6] + return int(_r_hex, 16), int(_g_hex, 16), int(_b_hex, 16) + + +# * Supported mice for the V1 chroma dock, can be adapted to support V2 +CHROMA_DOCK_MICE_NAMES = ["Razer Naga Pro", "Razer DeathAdder V2 Pro", "Razer Basilisk Ultimate", "Razer Viper Ultimate"] + +# * Battery % color gradient (0 - red, 100 - green) +GRADIENT = ( + {"color": "#220000", "position": 0}, + {"color": "#ff0000", "position": 20}, + {"color": "#ffa600", "position": 50}, + {"color": "#00ff00", "position": 100}, +) + +GRADIENT_RGB = [{"color": hex_to_rgb(_grad_clr["color"]), "position": _grad_clr["position"]} for _grad_clr in GRADIENT] + +POLL_DELAY_CONST = int(os.environ.get("RZR_SLEEPFOR", 360)) +QUICK_RETRIES_AMOUT = 6 # Does a shallow check, doesn't reinit dbus +FULL_RETRIES_AMOUT = 2 # Does a 'full' refresh (devices that weren't there before will now be shown); reinits DeviceManager + + +def pick_gradient_color(value: int | float, gradient_map: Sequence[dict]) -> tuple[int, int, int]: + """## Generates color based on the input value + + Define your gradient colors and positions with either floats or ints: + ``` + gradient = [ + {'color': '#03ee80', 'position': 0}, + {'color': '#ab77ff', 'position': 0.4}, + {'color': '#ff0040', 'position': 1} + ] + ``` + """ + # select value + for i in range(len(gradient_map) - 1): + if value <= gradient_map[i + 1]["position"]: + color1 = gradient_map[i]["color"] + color2 = gradient_map[i + 1]["color"] + position1 = gradient_map[i]["position"] + position2 = gradient_map[i + 1]["position"] + break + + # interpolated color based on the value + ratio = (value - position1) / (position2 - position1) + r = int(color1[0] + (color2[0] - color1[0]) * ratio) + g = int(color1[1] + (color2[1] - color1[1]) * ratio) + b = int(color1[2] + (color2[2] - color1[2]) * ratio) + + return r, g, b + + +def check_if_present(dock_device: RazerDevice, mouse_device: RazerDevice) -> bool: + """## Returns ``True`` if both the mouse and the dock are present""" + # * DPI values that are (0, 0) imply that the dongle is connected but the mouse is not. + if not (bool(mouse_device) and bool(dock_device)) or getattr(mouse_device, "dpi", None) == (0, 0): + if dock_device: + if dock_device.fx.effect != "breathSingle": + dock_device.fx.breath_single(50, 70, 255) + print(f"(One or more) required devices is not present:\n({mouse_device=}, {dock_device=})") + return False + return True + + +if __name__ == "__main__": + for _init_try in range(FULL_RETRIES_AMOUT): + dock_device = None + mouse_device = None + + devman = openrazer.client.DeviceManager() + devman.sync_effects = False + devices: list[RazerDevice] = devman.devices + + print(devices) + + for razer_device in devices: + if "Dock" in razer_device.name: + dock_device = razer_device + if any(_mouse_name in razer_device.name for _mouse_name in CHROMA_DOCK_MICE_NAMES): + mouse_device = razer_device + if not razer_device.battery_level: + continue + + print(f"{razer_device.name} is at {razer_device.battery_level}% battery.") + + _present = check_if_present(dock_device, mouse_device) + if not _present: + # ! I added the this logic because the mouse is not always connected upon OS startup + for _ in range(QUICK_RETRIES_AMOUT): + time.sleep(5) + _present = check_if_present(dock_device, mouse_device) + if _present: + break + else: + if _init_try == FULL_RETRIES_AMOUT - 1: + print(f"Startup failed, retried {QUICK_RETRIES_AMOUT * FULL_RETRIES_AMOUT} times") + if dock_device: + dock_device.fx.static(139, 0, 181) + exit(1) + else: + print(f"{QUICK_RETRIES_AMOUT} tries failed...") + continue + + dock_device.brightness = 100.0 + + while _present: + if not check_if_present(dock_device, mouse_device): + print("Retrying...") + time.sleep(5) + continue + + _gradient_color = pick_gradient_color(mouse_device.battery_level, GRADIENT_RGB) + print(f"Dock: {_gradient_color}; Mouse: {mouse_device.battery_level}%") + dock_device.fx.static(*_gradient_color) + time.sleep(POLL_DELAY_CONST) diff --git a/openrazer/examples/list_devices.py b/openrazer/examples/list_devices.py new file mode 100644 index 00000000..8ea2bf46 --- /dev/null +++ b/openrazer/examples/list_devices.py @@ -0,0 +1,18 @@ +from openrazer.client import DeviceManager + +# Create a DeviceManager. This is used to get specific devices +device_manager = DeviceManager() + + +print("Found {} Razer devices".format(len(device_manager.devices))) +print() + + +# Iterate over each device and pretty out some standard information about each +for device in device_manager.devices: + print("{}:".format(device.name)) + print(" type: {}".format(device.type)) + print(" serial: {}".format(device.serial)) + print(" firmware version: {}".format(device.firmware_version)) + print(" driver version: {}".format(device.driver_version)) + print() diff --git a/openrazer/install_files/appstream/io.github.openrazer.openrazer.metainfo.xml b/openrazer/install_files/appstream/io.github.openrazer.openrazer.metainfo.xml new file mode 100644 index 00000000..0b2f99c3 --- /dev/null +++ b/openrazer/install_files/appstream/io.github.openrazer.openrazer.metainfo.xml @@ -0,0 +1,268 @@ + + + io.github.openrazer.openrazer + CC0-1.0 + GPL-2.0+ + OpenRazer + Drivers for Razer peripherals on GNU/Linux + +

+ OpenRazer is a collection of GNU/Linux drivers for the Razer devices. + Supported devices include keyboards, mice, mouse-mats, headsets and + various other devices. OpenRazer provides kernel drivers, DBus services + and python bindings to interact with the DBus interface. +

+
+ https://openrazer.github.io/ + + #openrazer:matrix.org + https://fosstodon.org/@openrazer + + + usb:v1532p0013d* + usb:v1532p0015d* + usb:v1532p0016d* + usb:v1532p001Fd* + usb:v1532p0020d* + usb:v1532p0024d* + usb:v1532p0025d* + usb:v1532p0029d* + usb:v1532p002Ed* + usb:v1532p002Fd* + usb:v1532p0032d* + usb:v1532p0034d* + usb:v1532p0036d* + usb:v1532p0037d* + usb:v1532p0038d* + usb:v1532p0039d* + usb:v1532p003Ed* + usb:v1532p003Fd* + usb:v1532p0040d* + usb:v1532p0041d* + usb:v1532p0042d* + usb:v1532p0043d* + usb:v1532p0044d* + usb:v1532p0045d* + usb:v1532p0046d* + usb:v1532p0048d* + usb:v1532p004Cd* + usb:v1532p004Fd* + usb:v1532p0050d* + usb:v1532p0053d* + usb:v1532p0054d* + usb:v1532p0059d* + usb:v1532p005Ad* + usb:v1532p005Bd* + usb:v1532p005Cd* + usb:v1532p005Ed* + usb:v1532p0060d* + usb:v1532p0062d* + usb:v1532p0064d* + usb:v1532p0065d* + usb:v1532p0067d* + usb:v1532p0068d* + usb:v1532p006Ad* + usb:v1532p006Bd* + usb:v1532p006Cd* + usb:v1532p006Ed* + usb:v1532p006Fd* + usb:v1532p0070d* + usb:v1532p0071d* + usb:v1532p0072d* + usb:v1532p0073d* + usb:v1532p0077d* + usb:v1532p0078d* + usb:v1532p007Ad* + usb:v1532p007Bd* + usb:v1532p007Cd* + usb:v1532p007Dd* + usb:v1532p007Ed* + usb:v1532p0080d* + usb:v1532p0083d* + usb:v1532p0084d* + usb:v1532p0085d* + usb:v1532p0086d* + usb:v1532p0088d* + usb:v1532p008Ad* + usb:v1532p008Cd* + usb:v1532p008Dd* + usb:v1532p008Fd* + usb:v1532p0090d* + usb:v1532p0091d* + usb:v1532p0094d* + usb:v1532p0095d* + usb:v1532p0096d* + usb:v1532p0098d* + usb:v1532p0099d* + usb:v1532p009Ad* + usb:v1532p009Cd* + usb:v1532p009Ed* + usb:v1532p009Fd* + usb:v1532p00A1d* + usb:v1532p00A3d* + usb:v1532p00A5d* + usb:v1532p00A6d* + usb:v1532p00A7d* + usb:v1532p00A8d* + usb:v1532p00AAd* + usb:v1532p00ABd* + usb:v1532p00AFd* + usb:v1532p00B0d* + usb:v1532p00B2d* + usb:v1532p00B3d* + usb:v1532p00B4d* + usb:v1532p00B6d* + usb:v1532p00B7d* + usb:v1532p00B8d* + usb:v1532p00B9d* + usb:v1532p00C0d* + usb:v1532p00C1d* + usb:v1532p00C2d* + usb:v1532p00C3d* + usb:v1532p00C4d* + usb:v1532p00C5d* + usb:v1532p00C7d* + usb:v1532p00C8d* + usb:v1532p00CBd* + usb:v1532p00CCd* + usb:v1532p00CDd* + usb:v1532p010Dd* + usb:v1532p010Ed* + usb:v1532p010Fd* + usb:v1532p0111d* + usb:v1532p0113d* + usb:v1532p0118d* + usb:v1532p011Ad* + usb:v1532p011Bd* + usb:v1532p011Cd* + usb:v1532p0201d* + usb:v1532p0202d* + usb:v1532p0203d* + usb:v1532p0204d* + usb:v1532p0205d* + usb:v1532p0207d* + usb:v1532p0208d* + usb:v1532p0209d* + usb:v1532p020Fd* + usb:v1532p0210d* + usb:v1532p0211d* + usb:v1532p0214d* + usb:v1532p0215d* + usb:v1532p0216d* + usb:v1532p0217d* + usb:v1532p021Ad* + usb:v1532p021Ed* + usb:v1532p021Fd* + usb:v1532p0220d* + usb:v1532p0221d* + usb:v1532p0224d* + usb:v1532p0225d* + usb:v1532p0226d* + usb:v1532p0227d* + usb:v1532p0228d* + usb:v1532p022Ad* + usb:v1532p022Bd* + usb:v1532p022Cd* + usb:v1532p022Dd* + usb:v1532p022Fd* + usb:v1532p0232d* + usb:v1532p0233d* + usb:v1532p0234d* + usb:v1532p0235d* + usb:v1532p0237d* + usb:v1532p0239d* + usb:v1532p023Ad* + usb:v1532p023Bd* + usb:v1532p023Fd* + usb:v1532p0240d* + usb:v1532p0241d* + usb:v1532p0243d* + usb:v1532p0245d* + usb:v1532p0246d* + usb:v1532p024Ad* + usb:v1532p024Bd* + usb:v1532p024Cd* + usb:v1532p024Dd* + usb:v1532p024Ed* + usb:v1532p0252d* + usb:v1532p0253d* + usb:v1532p0255d* + usb:v1532p0256d* + usb:v1532p0257d* + usb:v1532p0258d* + usb:v1532p0259d* + usb:v1532p025Ad* + usb:v1532p025Cd* + usb:v1532p025Dd* + usb:v1532p025Ed* + usb:v1532p0266d* + usb:v1532p0268d* + usb:v1532p0269d* + usb:v1532p026Ad* + usb:v1532p026Bd* + usb:v1532p026Cd* + usb:v1532p026Dd* + usb:v1532p026Ed* + usb:v1532p026Fd* + usb:v1532p0270d* + usb:v1532p0271d* + usb:v1532p0276d* + usb:v1532p0279d* + usb:v1532p027Ad* + usb:v1532p0282d* + usb:v1532p0287d* + usb:v1532p028Ad* + usb:v1532p028Bd* + usb:v1532p028Cd* + usb:v1532p028Dd* + usb:v1532p028Fd* + usb:v1532p0290d* + usb:v1532p0292d* + usb:v1532p0293d* + usb:v1532p0294d* + usb:v1532p0295d* + usb:v1532p0296d* + usb:v1532p0298d* + usb:v1532p029Dd* + usb:v1532p029Ed* + usb:v1532p029Fd* + usb:v1532p02A0d* + usb:v1532p02A1d* + usb:v1532p02A2d* + usb:v1532p02A3d* + usb:v1532p02A5d* + usb:v1532p02A6d* + usb:v1532p02B6d* + usb:v1532p02B8d* + usb:v1532p02C6d* + usb:v1532p0501d* + usb:v1532p0504d* + usb:v1532p0506d* + usb:v1532p0510d* + usb:v1532p0517d* + usb:v1532p0518d* + usb:v1532p0527d* + usb:v1532p0560d* + usb:v1532p0A24d* + usb:v1532p0C00d* + usb:v1532p0C01d* + usb:v1532p0C02d* + usb:v1532p0C04d* + usb:v1532p0C05d* + usb:v1532p0C06d* + usb:v1532p0C08d* + usb:v1532p0F07d* + usb:v1532p0F08d* + usb:v1532p0F09d* + usb:v1532p0F0Dd* + usb:v1532p0F12d* + usb:v1532p0F19d* + usb:v1532p0F1Ad* + usb:v1532p0F1Dd* + usb:v1532p0F1Fd* + usb:v1532p0F20d* + usb:v1532p0F21d* + usb:v1532p0F26d* + usb:v1532p0F2Bd* + +
diff --git a/openrazer/install_files/desktop/openrazer-daemon.desktop b/openrazer/install_files/desktop/openrazer-daemon.desktop new file mode 100644 index 00000000..c0a921be --- /dev/null +++ b/openrazer/install_files/desktop/openrazer-daemon.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Name=OpenRazer Service +Comment=DBus daemon to abstract away from the driver and to provide more logic and integration with userspace stuffs. +Keywords=razer;keyboard;chroma; +NoDisplay=false +Exec=/usr/bin/openrazer-daemon --foreground --verbose +Icon=/usr/share/pixmaps/python3.xpm +Terminal=false +Type=Application +X-GNOME-Autostart-Phase=Applications +X-GNOME-AutoRestart=false +X-GNOME-UsesNotifications=true diff --git a/openrazer/install_files/dkms/dkms.conf b/openrazer/install_files/dkms/dkms.conf new file mode 100644 index 00000000..52985964 --- /dev/null +++ b/openrazer/install_files/dkms/dkms.conf @@ -0,0 +1,19 @@ +PACKAGE_NAME="openrazer-driver" +PACKAGE_VERSION="3.10.3" +AUTOINSTALL="yes" +MAKE="KERNELDIR=/lib/modules/${kernelver}/build make driver" + +BUILT_MODULE_NAME[0]="razerkbd" +BUILT_MODULE_NAME[1]="razermouse" +BUILT_MODULE_NAME[2]="razerkraken" +BUILT_MODULE_NAME[3]="razeraccessory" + +BUILT_MODULE_LOCATION[0]="driver" +BUILT_MODULE_LOCATION[1]="driver" +BUILT_MODULE_LOCATION[2]="driver" +BUILT_MODULE_LOCATION[3]="driver" + +DEST_MODULE_LOCATION[0]="/kernel/drivers/hid" +DEST_MODULE_LOCATION[1]="/kernel/drivers/hid" +DEST_MODULE_LOCATION[2]="/kernel/drivers/hid" +DEST_MODULE_LOCATION[3]="/kernel/drivers/hid" diff --git a/openrazer/install_files/udev/99-razer.rules b/openrazer/install_files/udev/99-razer.rules new file mode 100644 index 00000000..bdbd414e --- /dev/null +++ b/openrazer/install_files/udev/99-razer.rules @@ -0,0 +1,39 @@ +ACTION!="add", GOTO="razer_end" +SUBSYSTEMS=="usb|input|hid", ATTRS{idVendor}=="1532", GOTO="razer_vendor" +GOTO="razer_end" + +LABEL="razer_vendor" + +# Mice +ATTRS{idProduct}=="0013|0015|0016|001f|0020|0024|0025|0029|002e|002f|0032|0034|0036|0037|0038|0039|003e|003f|0040|0041|0042|0043|0044|0045|0046|0048|004c|004f|0050|0053|0054|0059|005a|005b|005c|005e|0060|0062|0064|0065|0067|006a|006b|006c|006e|006f|0070|0071|0072|0073|0077|0078|007a|007b|007c|007d|0080|0083|0084|0085|0086|0088|008a|008c|008d|008f|0090|0091|0094|0095|0096|0098|0099|009a|009c|009e|009f|00a1|00a3|00a5|00a6|00a7|00a8|00aa|00ab|00af|00b0|00b2|00b3|00b4|00b6|00b7|00b8|00b9|00c0|00c1|00c2|00c3|00c4|00c5|00c7|00c8|00cb|00cc|00cd", \ + ATTRS{idVendor}=="1532", \ + ENV{ID_RAZER_CHROMA}="1", ENV{RAZER_DRIVER}="razermouse" + +# Keyboards +ATTRS{idProduct}=="010d|010e|010f|0111|0113|0118|011a|011b|011c|0201|0202|0203|0204|0205|0207|0208|0209|020f|0210|0211|0214|0216|0217|021a|021e|021f|0220|0221|0224|0225|0226|0227|0228|022a|022b|022c|022d|022f|0232|0233|0234|0235|0237|0239|023a|023b|023f|0240|0241|0243|0245|0246|024a|024b|024c|024d|024e|0252|0253|0255|0256|0257|0258|0259|025a|025c|025d|025e|0266|0268|0269|026a|026b|026c|026d|026e|026f|0270|0271|0276|0279|027a|0282|0287|028a|028b|028c|028d|028f|0290|0292|0293|0294|0295|0296|0298|029d|029e|029f|02a0|02a1|02a2|02a3|02a5|02a6|02b6|02b8|02c6|0a24", \ + ATTRS{idVendor}=="1532", \ + ENV{ID_RAZER_CHROMA}="1", ENV{RAZER_DRIVER}="razerkbd" + +# Kraken +ATTRS{idProduct}=="0501|0504|0506|0510|0527|0560", \ + ATTRS{idVendor}=="1532", \ + ENV{ID_RAZER_CHROMA}="1", ENV{RAZER_DRIVER}="razerkraken" + +# Accessories (Speakers, Mousemats, Razer Core, etc) +ATTRS{idProduct}=="0068|007e|0215|0517|0518|0c00|0c01|0c02|0c04|0c05|0c06|0c08|0f07|0f08|0f09|0f0d|0f12|0f19|0f1a|0f1d|0f1f|0f20|0f21|0f26|0f2b", \ + ATTRS{idVendor}=="1532", \ + ENV{ID_RAZER_CHROMA}="1", ENV{RAZER_DRIVER}="razeraccessory" + +# Get out if no match +ENV{ID_RAZER_CHROMA}!="1", GOTO="razer_end" + +# Set permissions if this is an input node +SUBSYSTEM=="usb|input|hid", GROUP:="plugdev" + +# We're done unless it's the hid node +SUBSYSTEM!="hid|usb", GOTO="razer_end" + +# Rebind if needed +SUBSYSTEM=="hid|usb", RUN+="razer_mount $env{RAZER_DRIVER} $kernel" + +LABEL="razer_end" diff --git a/openrazer/install_files/udev/razer_mount b/openrazer/install_files/udev/razer_mount new file mode 100755 index 00000000..3fc0fef1 --- /dev/null +++ b/openrazer/install_files/udev/razer_mount @@ -0,0 +1,62 @@ +#!/bin/sh + +# Exit on error +set -e + +PATH='/sbin:/bin:/usr/sbin:/usr/bin' + +if [ -x /usr/bin/logger ]; then + LOGGER=/usr/bin/logger +elif [ -x /bin/logger ]; then + LOGGER=/bin/logger +else + unset LOGGER +fi + +# for diagnostics +if [ -t 1 -a -z "$LOGGER" ] || [ ! -e '/dev/log' ]; then + mesg() { + echo "$@" >&2 + } +elif [ -t 1 ]; then + mesg() { + echo "$@" + $LOGGER -t "${0##*/}[$$]" "$@" + } +else + mesg() { + $LOGGER -t "${0##*/}[$$]" "$@" + } +fi + +DRIVER=$1 +DEVICE_ID=$2 + +mesg "Driver $DRIVER" +mesg "Device_ID $DEVICE_ID" + +if [ ! -d /sys/bus/hid/drivers/"$DRIVER" ] ; then + mesg "Modprobing $DRIVER" + modprobe "$DRIVER" + sleep 0.05 + mesg "Modprobed $DRIVER" +fi + +for GENERIC_DRIVER in "razer" "hid-generic"; do + if [ -d /sys/bus/hid/drivers/"$GENERIC_DRIVER"/"$DEVICE_ID" ] ; then + # Unbind from hid + mesg "Unbinding $DEVICE_ID from $GENERIC_DRIVER" + printf '%s' "$DEVICE_ID" > /sys/bus/hid/drivers/"$GENERIC_DRIVER"/unbind + mesg "Binding $DEVICE_ID to $DRIVER" + printf '%s' "$DEVICE_ID" > /sys/bus/hid/drivers/"$DRIVER"/bind + sleep 0.1 + mesg "Finished binding $DEVICE_ID" + fi +done + +if [ -d /sys/bus/hid/drivers/"$DRIVER"/"$DEVICE_ID" ] ; then + mesg "Changing group /sys/bus/hid/drivers/$DRIVER/$DEVICE_ID/" + chgrp -R plugdev /sys/bus/hid/drivers/"$DRIVER"/"$DEVICE_ID"/ + mesg "Changed group /sys/bus/hid/drivers/$DRIVER/$DEVICE_ID/" +fi + diff --git a/openrazer/logo/openrazer-chroma.svg b/openrazer/logo/openrazer-chroma.svg new file mode 100644 index 00000000..e3558b1f --- /dev/null +++ b/openrazer/logo/openrazer-chroma.svg @@ -0,0 +1,491 @@ + + + + + OpenRazer "Chroma" Logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + OpenRazer "Chroma" Logo + + January 2016 + + + Luke Horwell + + + + + CC BY-SA 4.0 + + + A razer inspired "snake" logo created to represent the OpenRazer project. + +Source Code: https://github.com/openrazer/openrazer + + + Luke Horwell + + + + + Logo + Snakes + Keyboards + Tux Power + Linux. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openrazer/logo/openrazer-chroma.svg.license b/openrazer/logo/openrazer-chroma.svg.license new file mode 100644 index 00000000..a4d2346b --- /dev/null +++ b/openrazer/logo/openrazer-chroma.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015-2017 Luke Horwell + +SPDX-License-Identifier: CC-BY-SA-4.0 diff --git a/openrazer/logo/openrazer-static.svg b/openrazer/logo/openrazer-static.svg new file mode 100644 index 00000000..8d04f632 --- /dev/null +++ b/openrazer/logo/openrazer-static.svg @@ -0,0 +1,370 @@ + + + + + OpenRazer Logo + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + OpenRazer Logo + + January 2016 + + + Luke Horwell + + + + + CC BY-SA 4.0 + + + A razer inspired "snake" logo created to represent the OpenRazer project. + +Source Code: https://github.com/openrazer/openrazer + + + Luke Horwell + + + + + Logo + Snakes + Keyboards + Tux Power + Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openrazer/logo/openrazer-static.svg.license b/openrazer/logo/openrazer-static.svg.license new file mode 100644 index 00000000..a4d2346b --- /dev/null +++ b/openrazer/logo/openrazer-static.svg.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2015-2017 Luke Horwell + +SPDX-License-Identifier: CC-BY-SA-4.0 diff --git a/openrazer/pylib/Makefile b/openrazer/pylib/Makefile new file mode 100644 index 00000000..0ba9fe00 --- /dev/null +++ b/openrazer/pylib/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +DESTDIR?=/ +PREFIX?=/usr + +purge_pycache: + @find -name '__pycache__' | xargs rm -rf + +install: purge_pycache + python3 setup.py install --prefix=$(PREFIX) --root=$(DESTDIR) + +ubuntu_install: purge_pycache + python3 setup.py install --prefix=$(PREFIX) --root=$(DESTDIR) --no-compile --install-layout=deb diff --git a/openrazer/pylib/openrazer/__init__.py b/openrazer/pylib/openrazer/__init__.py new file mode 100644 index 00000000..315c06b6 --- /dev/null +++ b/openrazer/pylib/openrazer/__init__.py @@ -0,0 +1 @@ +# SPDX-License-Identifier: GPL-2.0-or-later diff --git a/openrazer/pylib/openrazer/_fake_driver/__init__.py b/openrazer/pylib/openrazer/_fake_driver/__init__.py new file mode 100644 index 00000000..e94f13bb --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/__init__.py @@ -0,0 +1,213 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import struct +import configparser +import glob +import os +import shutil + +SPECS = {os.path.splitext(os.path.basename(spec_file))[0]: spec_file for spec_file in glob.glob(os.path.join(os.path.dirname(__file__), '*.cfg'))} +EVENT_FORMAT = '@llHHI' +EV_KEY = 0x01 + +KEY_ACTION = { + 'up': 0x00, + 'down': 0x01, + 'repeat': 0x02 +} + + +def touch(fname, times=None): + with open(fname, 'a'): + os.utime(fname, times) + + +class FakeDevice(object): + @staticmethod + def parse_endpoint_line(line): + components = line.split(',') + + if len(components) == 2: + chmod, name = components + default = None + elif len(components) == 3: + chmod, name, default = components + else: + raise ValueError('Invalid config line "{0}"'.format(line)) + + orig_perm = chmod + + if chmod == 'r': + chmod = 0o660 + elif chmod == 'w': + chmod = 0o660 + else: + chmod = 0o660 + + return chmod, name, default, orig_perm + + @staticmethod + def create_endpoint(path, chmod, default=None): + if os.path.exists(path): + os.chmod(path, 0o660) + os.remove(path) + + if default is not None: + # Convert to bytes + if default.startswith("0x"): + default = bytes.fromhex(default[2:]) + else: + default = default.encode('UTF-8') + + with open(path, 'wb') as f: + f.write(default) + else: + touch(path) + os.chmod(path, chmod) + + def __init__(self, spec_name, serial=None, tmp_dir=os.environ.get('TMPDIR', '/tmp')): + + if spec_name not in SPECS: + raise ValueError("Spec {0} not in SPECS".format(spec_name)) + + self._tick = 1 + self.spec_name = spec_name + self._config = configparser.ConfigParser() + self._config.read(SPECS[spec_name]) + self._serial = serial + + self._tmp_dir = os.path.join(tmp_dir, self._config.get('device', 'dir_name')) + os.makedirs(self._tmp_dir, exist_ok=True) + + self.endpoints = {} + self.events = {} + self.create_endpoints() + self.create_events() + + if serial is not None: + self.set('device_serial', serial) + + # Disallow write in directory, so disallow creating new files after setup is done. + os.chmod(self._tmp_dir, 0o555) + + def _get_endpoint_path(self, endpoint): + return os.path.join(self._tmp_dir, endpoint) + + def _get_event_path(self, event): + return os.path.join(self._tmp_dir, 'input', event) + + def create_events(self): + """ + Goes through event files and creates them as needed + """ + event_files = self._config.get('device', 'event', fallback=None) + if event_files is None: + event_files = [] + else: + event_files = event_files.splitlines() + + for index, event_file in enumerate(event_files): + path = self._get_event_path(event_file) + + os.makedirs(os.path.dirname(path), exist_ok=True) + + if not os.path.exists(path): + os.mkfifo(path) + + file_object = os.open(path, os.O_RDWR) + + self.events[str(index)] = (event_file, file_object) + + def create_endpoints(self): + for endpoint_line in self._config.get('device', 'files').splitlines(): + chmod, name, default, orig_perm = self.parse_endpoint_line(endpoint_line) + path = self._get_endpoint_path(name) + + if name == 'device_serial' and self._serial is not None: + default = self._serial + self.endpoints[name] = (chmod, default, orig_perm) + self.create_endpoint(path, chmod, default) + + def get(self, endpoint, binary=False): + """ + Gets a value from a given endpoint + + :param endpoint: Endpoint to read from + :type endpoint: str + + :param binary: Is binary data being read + :type binary: bool + + :return: Result + :rtype: str or bytes + """ + if endpoint not in self.endpoints: + raise ValueError("Endpoint {0} does not exist".format(endpoint)) + + path = self._get_endpoint_path(endpoint) + + if binary: + read_mode = 'rb' + else: + read_mode = 'r' + + try: + with open(path, read_mode) as open_endpoint: + result = open_endpoint.read() + except UnicodeDecodeError as e: + return str(e) + + return result + + def set(self, endpoint, value, binary=False): + if endpoint not in self.endpoints: + raise ValueError("Endpoint {0} does not exist".format(endpoint)) + + path = self._get_endpoint_path(endpoint) + + if binary: + write_mode = 'wb' + else: + write_mode = 'w' + + with open(path, write_mode) as open_endpoint: + open_endpoint.write(value) + + def emit_kb_event(self, file_id, key_code, value): + + if file_id not in self.events: + raise ValueError("file_id {0} does not exist".format(file_id)) + + if value in KEY_ACTION: + value = KEY_ACTION[value] + else: + value = 0x00 + + event_binary = struct.pack(EVENT_FORMAT, self._tick, 0, EV_KEY, key_code, value) + pipe_fd = self.events[file_id][1] + os.write(pipe_fd, event_binary) + + return len(event_binary) + + def close(self): + if os.path.exists(self._tmp_dir): + # Allow deletion + for endpoint in self.endpoints: + path = os.path.join(self._tmp_dir, endpoint) + os.chmod(path, 0o660) + + # Allow write in directory again for cleanup + os.chmod(self._tmp_dir, 0o755) + + shutil.rmtree(self._tmp_dir) + + +if __name__ == '__main__': + + a = FakeDevice('razertartarus') + + print() + + a.emit_kb_event('0', 62, 'up') + + print() diff --git a/openrazer/pylib/openrazer/_fake_driver/razerabyssus1800.cfg b/openrazer/pylib/openrazer/_fake_driver/razerabyssus1800.cfg new file mode 100644 index 00000000..6bb19742 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerabyssus1800.cfg @@ -0,0 +1,14 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0020.0001 +name = Razer Abyssus 1800 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000020 + r,device_type,%(name)s + rw,dpi,30:30 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerabyssus2000.cfg b/openrazer/pylib/openrazer/_fake_driver/razerabyssus2000.cfg new file mode 100644 index 00000000..12e2a645 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerabyssus2000.cfg @@ -0,0 +1,14 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:005E.0001 +name = Razer Abyssus 2000 +files = rw,device_mode,0x0000 + r,device_serial,XX000000005E + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerabyssus2014.cfg b/openrazer/pylib/openrazer/_fake_driver/razerabyssus2014.cfg new file mode 100644 index 00000000..08ecec5b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerabyssus2014.cfg @@ -0,0 +1,13 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0042.0001 +name = Razer Abyssus 2014 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000042 + r,device_type,%(name)s + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerabyssuselited.vaedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerabyssuselited.vaedition.cfg new file mode 100644 index 00000000..67c97e71 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerabyssuselited.vaedition.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:006A.0001 +name = Razer Abyssus Elite (D.Va Edition) +files = rw,device_mode,0x0000 + r,device_serial,XX000000006A + 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 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerabyssusessential.cfg b/openrazer/pylib/openrazer/_fake_driver/razerabyssusessential.cfg new file mode 100644 index 00000000..90aa9bfa --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerabyssusessential.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:006B.0001 +name = Razer Abyssus Essential +files = rw,device_mode,0x0000 + r,device_serial,XX000000006B + 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 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerabyssusv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerabyssusv2.cfg new file mode 100644 index 00000000..a8d51b3e --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerabyssusv2.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:005B.0001 +name = Razer Abyssus V2 +files = rw,device_mode,0x0000 + r,device_serial,XX000000005B + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_blinking + w,logo_matrix_effect_breath + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_blinking + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razeranansi.cfg b/openrazer/pylib/openrazer/_fake_driver/razeranansi.cfg new file mode 100644 index 00000000..fd265a16 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razeranansi.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:010F.0001 +name = Razer Anansi +files = rw,device_mode,0x0000 + r,device_serial,XX000000010F + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razeratherisreceiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razeratherisreceiver.cfg new file mode 100644 index 00000000..b159583f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razeratherisreceiver.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0062.0001 +name = Razer Atheris (Receiver) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000062 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasestationchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasestationchroma.cfg new file mode 100644 index 00000000..53b17a78 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasestationchroma.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F08.0001 +name = Razer Base Station Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F08 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasestationv2chroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasestationv2chroma.cfg new file mode 100644 index 00000000..61c39eb1 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasestationv2chroma.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F20.0001 +name = Razer Base Station V2 Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F20 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasilisk.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasilisk.cfg new file mode 100644 index 00000000..11e74177 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasilisk.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0064.0001 +name = Razer Basilisk +files = rw,device_mode,0x0000 + r,device_serial,XX0000000064 + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskessential.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskessential.cfg new file mode 100644 index 00000000..3af2c9fe --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskessential.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0065.0001 +name = Razer Basilisk Essential +files = rw,device_mode,0x0000 + r,device_serial,XX0000000065 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskultimatereceiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskultimatereceiver.cfg new file mode 100644 index 00000000..d13f4043 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskultimatereceiver.cfg @@ -0,0 +1,49 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0088.0001 +name = Razer Basilisk Ultimate (Receiver) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000088 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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/openrazer/pylib/openrazer/_fake_driver/razerbasiliskultimatewired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskultimatewired.cfg new file mode 100644 index 00000000..2dffab0a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskultimatewired.cfg @@ -0,0 +1,47 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0086.0001 +name = Razer Basilisk Ultimate (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000086 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv2.cfg new file mode 100644 index 00000000..f6b63b8c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv2.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0085.0001 +name = Razer Basilisk V2 +files = rw,device_mode,0x0000 + 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/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3.cfg new file mode 100644 index 00000000..290c3dc4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3.cfg @@ -0,0 +1,33 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0099.0001 +name = Razer Basilisk V3 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000099 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_acceleration,0 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + rw,scroll_mode,0 + rw,scroll_smart_reel,0 + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv335k.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv335k.cfg new file mode 100644 index 00000000..4d240b56 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv335k.cfg @@ -0,0 +1,36 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00CB.0001 +name = Razer Basilisk V3 35K +files = rw,device_mode,0x0000 + r,device_serial,XX00000000CB + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_acceleration,0 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + rw,scroll_mode,0 + rw,scroll_smart_reel,0 + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3pro35kwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3pro35kwired.cfg new file mode 100644 index 00000000..6f0815cd --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3pro35kwired.cfg @@ -0,0 +1,40 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00CC.0001 +name = Razer Basilisk V3 Pro 35K (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000CC + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_acceleration,0 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + rw,scroll_mode,0 + rw,scroll_smart_reel,0 + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3pro35kwireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3pro35kwireless.cfg new file mode 100644 index 00000000..145dfcce --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3pro35kwireless.cfg @@ -0,0 +1,40 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00CD.0001 +name = Razer Basilisk V3 Pro 35K (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000CD + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_acceleration,0 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + rw,scroll_mode,0 + rw,scroll_smart_reel,0 + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3prowired.cfg new file mode 100644 index 00000000..ce11043c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3prowired.cfg @@ -0,0 +1,40 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00AA.0001 +name = Razer Basilisk V3 Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000AA + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_acceleration,0 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + rw,scroll_mode,0 + rw,scroll_smart_reel,0 + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3prowireless.cfg new file mode 100644 index 00000000..fe93000a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3prowireless.cfg @@ -0,0 +1,40 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00AB.0001 +name = Razer Basilisk V3 Pro (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000AB + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_acceleration,0 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + rw,scroll_mode,0 + rw,scroll_smart_reel,0 + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3xhyperspeed.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3xhyperspeed.cfg new file mode 100644 index 00000000..f7fa9d73 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskv3xhyperspeed.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B9.0001 +name = Razer Basilisk V3 X HyperSpeed +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000B9 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbasiliskxhyperspeed.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskxhyperspeed.cfg new file mode 100644 index 00000000..5b492b01 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbasiliskxhyperspeed.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0083.0001 +name = Razer Basilisk X HyperSpeed +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000083 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidow2019.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidow2019.cfg new file mode 100644 index 00000000..7aa23ba4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidow2019.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0241.0001 +name = Razer BlackWidow 2019 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000241 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchroma.cfg new file mode 100644 index 00000000..87ca8c2f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchroma.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0203.0001 +name = Razer BlackWidow Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000203 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromaoverwatch.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromaoverwatch.cfg new file mode 100644 index 00000000..ec8a4996 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromaoverwatch.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0211.0001 +name = Razer BlackWidow Chroma (Overwatch) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000211 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromatournamentedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromatournamentedition.cfg new file mode 100644 index 00000000..4b1f51d6 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromatournamentedition.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0209.0001 +name = Razer BlackWidow Chroma Tournament Edition +files = rw,device_mode,0x0000 + r,device_serial,XX0000000209 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromav2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromav2.cfg new file mode 100644 index 00000000..4c21faca --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowchromav2.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0221.0001 +name = Razer BlackWidow Chroma V2 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000221 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowelite.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowelite.cfg new file mode 100644 index 00000000..db310d01 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowelite.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0228.0001 +name = Razer BlackWidow Elite +files = rw,device_mode,0x0000 + r,device_serial,XX0000000228 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowessential.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowessential.cfg new file mode 100644 index 00000000..abb7bf74 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowessential.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0237.0001 +name = Razer BlackWidow Essential +files = rw,device_mode,0x0000 + r,device_serial,XX0000000237 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowlite.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowlite.cfg new file mode 100644 index 00000000..5f13c875 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowlite.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0235.0001 +name = Razer BlackWidow Lite +files = rw,device_mode,0x0000 + r,device_serial,XX0000000235 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowstealth.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowstealth.cfg new file mode 100644 index 00000000..c9ecee57 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowstealth.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:011B.0001 +name = Razer BlackWidow Stealth +files = rw,device_mode,0x0000 + r,device_serial,XX000000011B + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowstealthedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowstealthedition.cfg new file mode 100644 index 00000000..ea2c47cc --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowstealthedition.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:010E.0001 +name = Razer BlackWidow Stealth Edition +files = rw,device_mode,0x0000 + r,device_serial,XX000000010E + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowtournamentedition2014.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowtournamentedition2014.cfg new file mode 100644 index 00000000..5393d974 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowtournamentedition2014.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:011C.0001 +name = Razer BlackWidow Tournament Edition 2014 +files = rw,device_mode,0x0000 + r,device_serial,XX000000011C + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2012.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2012.cfg new file mode 100644 index 00000000..a50995d3 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2012.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:010D.0001 +name = Razer BlackWidow Ultimate 2012 +files = rw,device_mode,0x0000 + r,device_serial,XX000000010D + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2013.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2013.cfg new file mode 100644 index 00000000..dd1da575 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2013.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:011A.0001 +name = Razer BlackWidow Ultimate 2013 +files = rw,device_mode,0x0000 + r,device_serial,XX000000011A + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2016.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2016.cfg new file mode 100644 index 00000000..75a0bf66 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowultimate2016.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0214.0001 +name = Razer BlackWidow Ultimate 2016 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000214 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3.cfg new file mode 100644 index 00000000..95b4a838 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3.cfg @@ -0,0 +1,27 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:024E.0001 +name = Razer BlackWidow V3 +files = rw,device_mode,0x0000 + r,device_serial,XX000000024E + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3minihyperspeedwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3minihyperspeedwired.cfg new file mode 100644 index 00000000..277012a6 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3minihyperspeedwired.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0258.0001 +name = Razer BlackWidow V3 Mini Hyperspeed (Wired) +files = r,charge_level,255 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX0000000258 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3minihyperspeedwireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3minihyperspeedwireless.cfg new file mode 100644 index 00000000..bdff1d36 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3minihyperspeedwireless.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0271.0001 +name = Razer BlackWidow V3 Mini Hyperspeed (Wireless) +files = r,charge_level,255 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX0000000271 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3prowired.cfg new file mode 100644 index 00000000..6226c932 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3prowired.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:025A.0001 +name = Razer BlackWidow V3 Pro (Wired) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX000000025A + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3prowireless.cfg new file mode 100644 index 00000000..b7762686 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3prowireless.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:025C.0001 +name = Razer BlackWidow V3 Pro (Wireless) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX000000025C + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3tenkeyless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3tenkeyless.cfg new file mode 100644 index 00000000..67951821 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv3tenkeyless.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0A24.0001 +name = Razer BlackWidow V3 Tenkeyless +files = rw,device_mode,0x0000 + r,device_serial,XX0000000A24 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4.cfg new file mode 100644 index 00000000..e85c581d --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0287.0001 +name = Razer BlackWidow V4 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000287 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_effect_wheel + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv475pct.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv475pct.cfg new file mode 100644 index 00000000..8de8c5cd --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv475pct.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02A5.0001 +name = Razer BlackWidow V4 75%% +files = rw,device_mode,0x0000 + r,device_serial,XX00000002A5 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_effect_wheel + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4pro.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4pro.cfg new file mode 100644 index 00000000..47a10c14 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4pro.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:028D.0001 +name = Razer BlackWidow V4 Pro +files = rw,device_mode,0x0000 + r,device_serial,XX000000028D + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_effect_wheel + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4x.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4x.cfg new file mode 100644 index 00000000..b039a2d8 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowv4x.cfg @@ -0,0 +1,25 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0293.0001 +name = Razer BlackWidow V4 X +files = rw,device_mode,0x0000 + r,device_serial,XX0000000293 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_effect_wheel + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxchroma.cfg new file mode 100644 index 00000000..53856622 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxchroma.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0216.0001 +name = Razer BlackWidow X Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000216 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxchromatournamentedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxchromatournamentedition.cfg new file mode 100644 index 00000000..612e4b7b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxchromatournamentedition.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:021A.0001 +name = Razer BlackWidow X Chroma Tournament Edition +files = rw,device_mode,0x0000 + r,device_serial,XX000000021A + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxultimate.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxultimate.cfg new file mode 100644 index 00000000..6e8ee183 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblackwidowxultimate.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0217.0001 +name = Razer BlackWidow X Ultimate +files = rw,device_mode,0x0000 + r,device_serial,XX0000000217 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade142021.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade142021.cfg new file mode 100644 index 00000000..8e54aeff --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade142021.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0270.0001 +name = Razer Blade 14 (2021) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000270 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade142022.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade142022.cfg new file mode 100644 index 00000000..8a85a35c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade142022.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:028C.0001 +name = Razer Blade 14 (2022) +files = rw,device_mode,0x0000 + r,device_serial,XX000000028C + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade142023.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade142023.cfg new file mode 100644 index 00000000..dc07b6a7 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade142023.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:029D.0001 +name = Razer Blade 14 (2023) +files = rw,device_mode,0x0000 + r,device_serial,XX000000029D + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade142024.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade142024.cfg new file mode 100644 index 00000000..0bc77f8f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade142024.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02B6.0001 +name = Razer Blade 14 (2024) +files = rw,device_mode,0x0000 + r,device_serial,XX00000002B6 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade152018.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade152018.cfg new file mode 100644 index 00000000..93cf67d8 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade152018.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0233.0001 +name = Razer Blade 15 (2018) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000233 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade152018basemodel.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade152018basemodel.cfg new file mode 100644 index 00000000..4b0a681a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade152018basemodel.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:023B.0001 +name = Razer Blade 15 (2018) Base Model +files = rw,device_mode,0x0000 + r,device_serial,XX000000023B + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade152018mercury.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade152018mercury.cfg new file mode 100644 index 00000000..9e4a8925 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade152018mercury.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0240.0001 +name = Razer Blade 15 (2018) Mercury +files = rw,device_mode,0x0000 + r,device_serial,XX0000000240 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade152019advanced.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade152019advanced.cfg new file mode 100644 index 00000000..da8d0427 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade152019advanced.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:023A.0001 +name = Razer Blade 15 (2019) Advanced +files = rw,device_mode,0x0000 + r,device_serial,XX000000023A + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade152019basemodel.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade152019basemodel.cfg new file mode 100644 index 00000000..972bbe4c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade152019basemodel.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0246.0001 +name = Razer Blade 15 (2019) Base Model +files = rw,device_mode,0x0000 + r,device_serial,XX0000000246 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade152023.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade152023.cfg new file mode 100644 index 00000000..88845200 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade152023.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:029E.0001 +name = Razer Blade 15 (2023) +files = rw,device_mode,0x0000 + r,device_serial,XX000000029E + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15advanced2020.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15advanced2020.cfg new file mode 100644 index 00000000..95136e1c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15advanced2020.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0253.0001 +name = Razer Blade 15 Advanced (2020) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000253 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedearly2021.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedearly2021.cfg new file mode 100644 index 00000000..dabc2620 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedearly2021.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:026D.0001 +name = Razer Blade 15 Advanced (Early 2021) +files = rw,device_mode,0x0000 + r,device_serial,XX000000026D + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedearly2022.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedearly2022.cfg new file mode 100644 index 00000000..d9888e99 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedearly2022.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:028A.0001 +name = Razer Blade 15 Advanced (Early 2022) +files = rw,device_mode,0x0000 + r,device_serial,XX000000028A + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedmid2021.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedmid2021.cfg new file mode 100644 index 00000000..541de1cd --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15advancedmid2021.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0276.0001 +name = Razer Blade 15 Advanced (Mid 2021) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000276 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15base2022.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15base2022.cfg new file mode 100644 index 00000000..168dcebc --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15base2022.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:027A.0001 +name = Razer Blade 15 Base (2022) +files = rw,device_mode,0x0000 + r,device_serial,XX000000027A + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15baseearly2020.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15baseearly2020.cfg new file mode 100644 index 00000000..bb45a04a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15baseearly2020.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0255.0001 +name = Razer Blade 15 Base (Early 2020) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000255 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15baseearly2021.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15baseearly2021.cfg new file mode 100644 index 00000000..c8d1fe6e --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15baseearly2021.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:026F.0001 +name = Razer Blade 15 Base (Early 2021) +files = rw,device_mode,0x0000 + r,device_serial,XX000000026F + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15baselate2020.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15baselate2020.cfg new file mode 100644 index 00000000..23be6971 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15baselate2020.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0268.0001 +name = Razer Blade 15 Base (Late 2020) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000268 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15mid2019mercurywhite.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15mid2019mercurywhite.cfg new file mode 100644 index 00000000..95a207b9 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15mid2019mercurywhite.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0245.0001 +name = Razer Blade 15 (Mid 2019) Mercury White +files = rw,device_mode,0x0000 + r,device_serial,XX0000000245 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade15studioedition2019.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade15studioedition2019.cfg new file mode 100644 index 00000000..e6677233 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade15studioedition2019.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:024D.0001 +name = Razer Blade 15 Studio Edition (2019) +files = rw,device_mode,0x0000 + r,device_serial,XX000000024D + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade162023.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade162023.cfg new file mode 100644 index 00000000..57b929da --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade162023.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:029F.0001 +name = Razer Blade 16 (2023) +files = rw,device_mode,0x0000 + r,device_serial,XX000000029F + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade162025.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade162025.cfg new file mode 100644 index 00000000..63908f89 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade162025.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02C6.0001 +name = Razer Blade 16 (2025) +files = rw,device_mode,0x0000 + r,device_serial,XX00000002C6 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade172022.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade172022.cfg new file mode 100644 index 00000000..95bd3895 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade172022.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:028B.0001 +name = Razer Blade 17 (2022) +files = rw,device_mode,0x0000 + r,device_serial,XX000000028B + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade17proearly2021.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade17proearly2021.cfg new file mode 100644 index 00000000..9c184917 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade17proearly2021.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:026E.0001 +name = Razer Blade 17 Pro (Early 2021) +files = rw,device_mode,0x0000 + r,device_serial,XX000000026E + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade17promid2021.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade17promid2021.cfg new file mode 100644 index 00000000..ffcbeb1c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade17promid2021.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0279.0001 +name = Razer Blade 17 Pro (Mid 2021) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000279 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade182023.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade182023.cfg new file mode 100644 index 00000000..28b62d34 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade182023.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02A0.0001 +name = Razer Blade 18 (2023) +files = rw,device_mode,0x0000 + r,device_serial,XX00000002A0 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerblade182024.cfg b/openrazer/pylib/openrazer/_fake_driver/razerblade182024.cfg new file mode 100644 index 00000000..0b628213 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerblade182024.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02B8.0001 +name = Razer Blade 18 (2024) +files = rw,device_mode,0x0000 + r,device_serial,XX00000002B8 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladeadvancedlate2019.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladeadvancedlate2019.cfg new file mode 100644 index 00000000..a78dd0b1 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladeadvancedlate2019.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:024B.0001 +name = Razer Blade Advanced (Late 2019) +files = rw,device_mode,0x0000 + r,device_serial,XX000000024B + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladelate2016.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladelate2016.cfg new file mode 100644 index 00000000..a8b54b5a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladelate2016.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0224.0001 +name = Razer Blade (Late 2016) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000224 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladepro2017.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladepro2017.cfg new file mode 100644 index 00000000..b1fa780c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladepro2017.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0225.0001 +name = Razer Blade Pro (2017) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000225 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladepro2019.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladepro2019.cfg new file mode 100644 index 00000000..8d4d0e2c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladepro2019.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0234.0001 +name = Razer Blade Pro (2019) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000234 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladeproearly2020.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladeproearly2020.cfg new file mode 100644 index 00000000..8f8a54df --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladeproearly2020.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0256.0001 +name = Razer Blade Pro (Early 2020) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000256 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladeprofullhd2017.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladeprofullhd2017.cfg new file mode 100644 index 00000000..27724f64 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladeprofullhd2017.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:022F.0001 +name = Razer Blade Pro FullHD (2017) +files = rw,device_mode,0x0000 + r,device_serial,XX000000022F + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladeprolate2016.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladeprolate2016.cfg new file mode 100644 index 00000000..8aad179d --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladeprolate2016.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0210.0001 +name = Razer Blade Pro (Late 2016) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000210 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladeprolate2019.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladeprolate2019.cfg new file mode 100644 index 00000000..97b3de04 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladeprolate2019.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:024C.0001 +name = Razer Blade Pro (Late 2019) +files = rw,device_mode,0x0000 + r,device_serial,XX000000024C + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealth.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealth.cfg new file mode 100644 index 00000000..51a4f0ce --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealth.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0205.0001 +name = Razer Blade Stealth +files = rw,device_mode,0x0000 + r,device_serial,XX0000000205 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealth2019.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealth2019.cfg new file mode 100644 index 00000000..8feaf28d --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealth2019.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0239.0001 +name = Razer Blade Stealth (2019) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000239 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealthearly2020.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthearly2020.cfg new file mode 100644 index 00000000..eb3b80f3 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthearly2020.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0252.0001 +name = Razer Blade Stealth (Early 2020) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000252 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2016.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2016.cfg new file mode 100644 index 00000000..9bf809f9 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2016.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0220.0001 +name = Razer Blade Stealth (Late 2016) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000220 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2017.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2017.cfg new file mode 100644 index 00000000..3bc6b54b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2017.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0232.0001 +name = Razer Blade Stealth (Late 2017) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000232 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2019.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2019.cfg new file mode 100644 index 00000000..fffeeeb8 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2019.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:024A.0001 +name = Razer Blade Stealth (Late 2019) +files = rw,device_mode,0x0000 + r,device_serial,XX000000024A + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2020.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2020.cfg new file mode 100644 index 00000000..c0ab05f1 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthlate2020.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0259.0001 +name = Razer Blade Stealth (Late 2020) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000259 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealthmid2017.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthmid2017.cfg new file mode 100644 index 00000000..83e56be5 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthmid2017.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:022D.0001 +name = Razer Blade Stealth (Mid 2017) +files = rw,device_mode,0x0000 + r,device_serial,XX000000022D + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbladestealthqhd.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthqhd.cfg new file mode 100644 index 00000000..ee43dd03 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbladestealthqhd.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:020F.0001 +name = Razer Blade Stealth (QHD) +files = rw,device_mode,0x0000 + r,device_serial,XX000000020F + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,logo_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerbook132020.cfg b/openrazer/pylib/openrazer/_fake_driver/razerbook132020.cfg new file mode 100644 index 00000000..15358dc8 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerbook132020.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:026A.0001 +name = Razer Book 13 (2020) +files = rw,device_mode,0x0000 + r,device_serial,XX000000026A + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerchargingpadchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerchargingpadchroma.cfg new file mode 100644 index 00000000..c6cf6f2b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerchargingpadchroma.cfg @@ -0,0 +1,36 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F26.0001 +name = Razer Charging Pad Chroma +files = rw,charging_led_brightness,0 + w,charging_matrix_effect_breath + w,charging_matrix_effect_none + w,charging_matrix_effect_spectrum + w,charging_matrix_effect_static + w,charging_matrix_effect_wave + rw,device_mode,0x0000 + r,device_serial,XX0000000F26 + r,device_type,%(name)s + rw,fast_charging_led_brightness,0 + w,fast_charging_matrix_effect_breath + w,fast_charging_matrix_effect_none + w,fast_charging_matrix_effect_spectrum + w,fast_charging_matrix_effect_static + w,fast_charging_matrix_effect_wave + r,firmware_version,v1.0 + rw,fully_charged_led_brightness,0 + w,fully_charged_matrix_effect_breath + w,fully_charged_matrix_effect_none + w,fully_charged_matrix_effect_spectrum + w,fully_charged_matrix_effect_static + w,fully_charged_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerchromaaddressablergbcontroller.cfg b/openrazer/pylib/openrazer/_fake_driver/razerchromaaddressablergbcontroller.cfg new file mode 100644 index 00000000..93c8c903 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerchromaaddressablergbcontroller.cfg @@ -0,0 +1,31 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F1F.0001 +name = Razer Chroma Addressable RGB Controller +files = rw,channel1_led_brightness,0 + rw,channel1_size,8 + rw,channel2_led_brightness,0 + rw,channel2_size,8 + rw,channel3_led_brightness,0 + rw,channel3_size,8 + rw,channel4_led_brightness,0 + rw,channel4_size,8 + rw,channel5_led_brightness,0 + rw,channel5_size,8 + rw,channel6_led_brightness,0 + rw,channel6_size,8 + rw,device_mode,0x0000 + r,device_serial,XX0000000F1F + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + w,reset_channels,1 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerchromahdk.cfg b/openrazer/pylib/openrazer/_fake_driver/razerchromahdk.cfg new file mode 100644 index 00000000..abea52d9 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerchromahdk.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F09.0001 +name = Razer Chroma HDK +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F09 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerchromamugholder.cfg b/openrazer/pylib/openrazer/_fake_driver/razerchromamugholder.cfg new file mode 100644 index 00000000..9086487c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerchromamugholder.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F07.0001 +name = Razer Chroma Mug Holder +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F07 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,is_mug_present,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_blinking + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercobra.cfg b/openrazer/pylib/openrazer/_fake_driver/razercobra.cfg new file mode 100644 index 00000000..47f19e56 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercobra.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00A3.0001 +name = Razer Cobra +files = rw,device_mode,0x0000 + r,device_serial,XX00000000A3 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercobraprowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razercobraprowired.cfg new file mode 100644 index 00000000..325b036b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercobraprowired.cfg @@ -0,0 +1,32 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00AF.0001 +name = Razer Cobra Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000AF + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercobraprowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razercobraprowireless.cfg new file mode 100644 index 00000000..9d87201c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercobraprowireless.cfg @@ -0,0 +1,32 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B0.0001 +name = Razer Cobra Pro (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000B0 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + w,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercore.cfg b/openrazer/pylib/openrazer/_fake_driver/razercore.cfg new file mode 100644 index 00000000..3bc3885b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercore.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0215.0001 +name = Razer Core +files = rw,device_mode,0x0000 + r,device_serial,XX0000000215 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercorexchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razercorexchroma.cfg new file mode 100644 index 00000000..39bbc967 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercorexchroma.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F1A.0001 +name = Razer Core X Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F1A + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercynosachroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razercynosachroma.cfg new file mode 100644 index 00000000..99d2838a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercynosachroma.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:022A.0001 +name = Razer Cynosa Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX000000022A + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercynosachromapro.cfg b/openrazer/pylib/openrazer/_fake_driver/razercynosachromapro.cfg new file mode 100644 index 00000000..f7e1814d --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercynosachromapro.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:022C.0001 +name = Razer Cynosa Chroma Pro +files = rw,device_mode,0x0000 + r,device_serial,XX000000022C + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercynosalite.cfg b/openrazer/pylib/openrazer/_fake_driver/razercynosalite.cfg new file mode 100644 index 00000000..2f2ddcb7 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercynosalite.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:023F.0001 +name = Razer Cynosa Lite +files = rw,device_mode,0x0000 + r,device_serial,XX000000023F + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razercynosav2.cfg b/openrazer/pylib/openrazer/_fake_driver/razercynosav2.cfg new file mode 100644 index 00000000..2578f881 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razercynosav2.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:025E.0001 +name = Razer Cynosa V2 +files = rw,device_mode,0x0000 + r,device_serial,XX000000025E + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadder1800.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder1800.cfg new file mode 100644 index 00000000..bf5284f1 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder1800.cfg @@ -0,0 +1,14 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0038.0001 +name = Razer DeathAdder 1800 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000038 + r,device_type,%(name)s + rw,dpi,30:30 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadder2000.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder2000.cfg new file mode 100644 index 00000000..e4992b29 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder2000.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:004F.0001 +name = Razer DeathAdder 2000 +files = rw,device_mode,0x0000 + r,device_serial,XX000000004F + 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_on + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadder2013.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder2013.cfg new file mode 100644 index 00000000..3fa2d6e1 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder2013.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0037.0001 +name = Razer DeathAdder 2013 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000037 + r,device_type,%(name)s + rw,dpi,30:30 + r,firmware_version,v1.0 + w,logo_matrix_effect_blinking + w,logo_matrix_effect_breath + w,logo_matrix_effect_none + w,logo_matrix_effect_static + rw,poll_rate,500 + w,scroll_matrix_effect_blinking + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3.5g.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3.5g.cfg new file mode 100644 index 00000000..fd795936 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3.5g.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0016.0001 +name = Razer DeathAdder 3.5G +files = rw,device_mode,0x0000 + r,device_serial,XX0000000016 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3.5gblack.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3.5gblack.cfg new file mode 100644 index 00000000..deb6f6e4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3.5gblack.cfg @@ -0,0 +1,12 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0029.0001 +name = Razer DeathAdder 3.5G Black +files = rw,device_mode,0x0000 + r,device_serial,XX0000000029 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3500.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3500.cfg new file mode 100644 index 00000000..709284f8 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadder3500.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0054.0001 +name = Razer DeathAdder 3500 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000054 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_blinking + w,logo_matrix_effect_breath + w,logo_matrix_effect_none + w,logo_matrix_effect_static + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_blinking + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderchroma.cfg new file mode 100644 index 00000000..01aef11c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderchroma.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0043.0001 +name = Razer DeathAdder Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000043 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,logo_led_brightness,0 + w,logo_matrix_effect_blinking + w,logo_matrix_effect_breath + w,logo_matrix_effect_none + w,logo_matrix_effect_spectrum + w,logo_matrix_effect_static + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_blinking + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderelite.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderelite.cfg new file mode 100644 index 00000000..6cd5292b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderelite.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:005C.0001 +name = Razer DeathAdder Elite +files = rw,device_mode,0x0000 + r,device_serial,XX000000005C + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessential.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessential.cfg new file mode 100644 index 00000000..2c905c46 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessential.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:006E.0001 +name = Razer DeathAdder Essential +files = rw,device_mode,0x0000 + r,device_serial,XX000000006E + 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_static + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessential2021.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessential2021.cfg new file mode 100644 index 00000000..cf6c5b90 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessential2021.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0098.0001 +name = Razer DeathAdder Essential (2021) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000098 + 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_static + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessentialwhiteedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessentialwhiteedition.cfg new file mode 100644 index 00000000..66f4a14f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderessentialwhiteedition.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0071.0001 +name = Razer DeathAdder Essential (White Edition) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000071 + 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_static + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2.cfg new file mode 100644 index 00000000..4d974955 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0084.0001 +name = Razer DeathAdder V2 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000084 + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2lite.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2lite.cfg new file mode 100644 index 00000000..8c0f004c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2lite.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00A1.0001 +name = Razer DeathAdder V2 Lite +files = rw,device_mode,0x0000 + r,device_serial,XX00000000A1 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2mini.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2mini.cfg new file mode 100644 index 00000000..2bb5d765 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2mini.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:008C.0001 +name = Razer DeathAdder V2 Mini +files = rw,device_mode,0x0000 + r,device_serial,XX000000008C + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2prowired.cfg new file mode 100644 index 00000000..bd1f3227 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2prowired.cfg @@ -0,0 +1,25 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:007C.0001 +name = Razer DeathAdder V2 Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000007C + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2prowireless.cfg new file mode 100644 index 00000000..7bcc2832 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2prowireless.cfg @@ -0,0 +1,27 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:007D.0001 +name = Razer DeathAdder V2 Pro (Wireless) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000007D + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2xhyperspeed.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2xhyperspeed.cfg new file mode 100644 index 00000000..2286c19d --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv2xhyperspeed.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:009C.0001 +name = Razer DeathAdder V2 X HyperSpeed +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000009C + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3.cfg new file mode 100644 index 00000000..9a34ed66 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3.cfg @@ -0,0 +1,13 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B2.0001 +name = Razer DeathAdder V3 +files = rw,device_mode,0x0000 + r,device_serial,XX00000000B2 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3hyperspeedwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3hyperspeedwired.cfg new file mode 100644 index 00000000..8abc37a3 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3hyperspeedwired.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C4.0001 +name = Razer DeathAdder V3 HyperSpeed (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C4 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3hyperspeedwireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3hyperspeedwireless.cfg new file mode 100644 index 00000000..cf5dcb3a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3hyperspeedwireless.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C5.0001 +name = Razer DeathAdder V3 HyperSpeed (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C5 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowired.cfg new file mode 100644 index 00000000..514747bb --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowired.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B6.0001 +name = Razer DeathAdder V3 Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000B6 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowired_2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowired_2.cfg new file mode 100644 index 00000000..ed5470c7 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowired_2.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C2.0001 +name = Razer DeathAdder V3 Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C2 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowireless.cfg new file mode 100644 index 00000000..4b6630a4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowireless.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B7.0001 +name = Razer DeathAdder V3 Pro (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000B7 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowireless_2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowireless_2.cfg new file mode 100644 index 00000000..b5bfbe35 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathadderv3prowireless_2.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C3.0001 +name = Razer DeathAdder V3 Pro (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C3 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerchroma.cfg new file mode 100644 index 00000000..1b4f0d6e --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerchroma.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0204.0001 +name = Razer DeathStalker Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000204 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkeressential.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkeressential.cfg new file mode 100644 index 00000000..9e1b87ba --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkeressential.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0118.0001 +name = Razer Deathstalker (Essential) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000118 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerexpert.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerexpert.cfg new file mode 100644 index 00000000..4e0109cb --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerexpert.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0202.0001 +name = Razer Deathstalker Expert +files = rw,device_mode,0x0000 + r,device_serial,XX0000000202 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2.cfg new file mode 100644 index 00000000..22ab1f8b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2.cfg @@ -0,0 +1,27 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0295.0001 +name = Razer DeathStalker V2 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000295 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2protklwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2protklwired.cfg new file mode 100644 index 00000000..1e3b4853 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2protklwired.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0298.0001 +name = Razer DeathStalker V2 Pro TKL (Wired) +files = r,charge_level,255 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX0000000298 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2protklwireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2protklwireless.cfg new file mode 100644 index 00000000..161964a6 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2protklwireless.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0296.0001 +name = Razer DeathStalker V2 Pro TKL (Wireless) +files = r,charge_level,255 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX0000000296 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2prowired.cfg new file mode 100644 index 00000000..8c0d291b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2prowired.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0292.0001 +name = Razer DeathStalker V2 Pro (Wired) +files = r,charge_level,255 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX0000000292 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2prowireless.cfg new file mode 100644 index 00000000..ac60fa10 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdeathstalkerv2prowireless.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0290.0001 +name = Razer DeathStalker V2 Pro (Wireless) +files = r,charge_level,255 + r,charge_status,1 + rw,device_mode,0x0000 + r,device_serial,XX0000000290 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerdiamondbackchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerdiamondbackchroma.cfg new file mode 100644 index 00000000..634a0daa --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerdiamondbackchroma.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:004C.0001 +name = Razer Diamondback Chroma +files = rw,backlight_led_brightness,0 + w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_reactive + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + w,backlight_matrix_effect_wave + rw,device_mode,0x0000 + r,device_serial,XX000000004C + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,matrix_custom_frame + w,matrix_effect_custom + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerfirefly.cfg b/openrazer/pylib/openrazer/_fake_driver/razerfirefly.cfg new file mode 100644 index 00000000..a321642f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerfirefly.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0C00.0001 +name = Razer Firefly +files = rw,device_mode,0x0000 + r,device_serial,XX0000000C00 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerfireflyhyperflux.cfg b/openrazer/pylib/openrazer/_fake_driver/razerfireflyhyperflux.cfg new file mode 100644 index 00000000..c568b557 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerfireflyhyperflux.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0068.0001 +name = Razer Firefly Hyperflux +files = rw,device_mode,0x0000 + r,device_serial,XX0000000068 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerfireflyv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerfireflyv2.cfg new file mode 100644 index 00000000..f6d99d8a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerfireflyv2.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0C04.0001 +name = Razer Firefly V2 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000C04 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerfireflyv2pro.cfg b/openrazer/pylib/openrazer/_fake_driver/razerfireflyv2pro.cfg new file mode 100644 index 00000000..16a79c5f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerfireflyv2pro.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0C08.0001 +name = Razer Firefly V2 Pro +files = rw,device_mode,0x0000 + r,device_serial,XX0000000C08 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razergoliathus.cfg b/openrazer/pylib/openrazer/_fake_driver/razergoliathus.cfg new file mode 100644 index 00000000..227af22a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razergoliathus.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0C01.0001 +name = Razer Goliathus +files = rw,device_mode,0x0000 + r,device_serial,XX0000000C01 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razergoliathuschroma3xl.cfg b/openrazer/pylib/openrazer/_fake_driver/razergoliathuschroma3xl.cfg new file mode 100644 index 00000000..49af32c6 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razergoliathuschroma3xl.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0C06.0001 +name = Razer Goliathus Chroma 3XL +files = rw,device_mode,0x0000 + r,device_serial,XX0000000C06 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razergoliathusextended.cfg b/openrazer/pylib/openrazer/_fake_driver/razergoliathusextended.cfg new file mode 100644 index 00000000..0c1cac5a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razergoliathusextended.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0C02.0001 +name = Razer Goliathus Extended +files = rw,device_mode,0x0000 + r,device_serial,XX0000000C02 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsman.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsman.cfg new file mode 100644 index 00000000..3f07a4eb --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsman.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0227.0001 +name = Razer Huntsman +files = rw,device_mode,0x0000 + r,device_serial,XX0000000227 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanelite.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanelite.cfg new file mode 100644 index 00000000..9cb6dd98 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanelite.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0226.0001 +name = Razer Huntsman Elite +files = rw,device_mode,0x0000 + r,device_serial,XX0000000226 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanmini.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanmini.cfg new file mode 100644 index 00000000..b96e9de4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanmini.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0257.0001 +name = Razer Huntsman Mini +files = rw,device_mode,0x0000 + r,device_serial,XX0000000257 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanminianalog.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanminianalog.cfg new file mode 100644 index 00000000..cb3076c2 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanminianalog.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0282.0001 +name = Razer Huntsman Mini Analog +files = rw,device_mode,0x0000 + r,device_serial,XX0000000282 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanminijp.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanminijp.cfg new file mode 100644 index 00000000..d2023efe --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanminijp.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0269.0001 +name = Razer Huntsman Mini (JP) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000269 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmantournamentedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmantournamentedition.cfg new file mode 100644 index 00000000..0f4357cd --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmantournamentedition.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0243.0001 +name = Razer Huntsman Tournament Edition +files = rw,device_mode,0x0000 + r,device_serial,XX0000000243 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2.cfg new file mode 100644 index 00000000..86e02159 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:026C.0001 +name = Razer Huntsman V2 +files = rw,device_mode,0x0000 + r,device_serial,XX000000026C + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,keyswitch_optimization,0 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2analog.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2analog.cfg new file mode 100644 index 00000000..7ac293cf --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2analog.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0266.0001 +name = Razer Huntsman V2 Analog +files = rw,device_mode,0x0000 + r,device_serial,XX0000000266 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2tenkeyless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2tenkeyless.cfg new file mode 100644 index 00000000..63b20565 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv2tenkeyless.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:026B.0001 +name = Razer Huntsman V2 Tenkeyless +files = rw,device_mode,0x0000 + r,device_serial,XX000000026B + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,key_alt_f4,0x00 + rw,key_alt_tab,0x00 + rw,key_super,0x00 + rw,keyswitch_optimization,0 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv3pro.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv3pro.cfg new file mode 100644 index 00000000..e193a17b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhuntsmanv3pro.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02A6.0001 +name = Razer Huntsman V3 Pro +files = rw,device_mode,0x0000 + r,device_serial,XX00000002A6 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerhyperpollingwirelessdongle.cfg b/openrazer/pylib/openrazer/_fake_driver/razerhyperpollingwirelessdongle.cfg new file mode 100644 index 00000000..5ab66bf6 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerhyperpollingwirelessdongle.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B3.0001 +name = Razer HyperPolling Wireless Dongle +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000B3 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + w,hyperpolling_wireless_dongle_indicator_led_mode + w,hyperpolling_wireless_dongle_pair + w,hyperpolling_wireless_dongle_unpair + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerimperator2012.cfg b/openrazer/pylib/openrazer/_fake_driver/razerimperator2012.cfg new file mode 100644 index 00000000..4c64f682 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerimperator2012.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:002F.0001 +name = Razer Imperator 2012 +files = rw,device_mode,0x0000 + r,device_serial,XX000000002F + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1.cfg b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1.cfg new file mode 100644 index 00000000..d985016d --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1.cfg @@ -0,0 +1,13 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0501.0001 +name = Razer Kraken 7.1 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000501 + r,device_type,%(name)s + r,firmware_version,v1.0 + w,matrix_current_effect,05 + w,matrix_effect_none + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1_2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1_2.cfg new file mode 100644 index 00000000..e575234f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1_2.cfg @@ -0,0 +1,13 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0506.0001 +name = Razer Kraken 7.1 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000506 + r,device_type,%(name)s + r,firmware_version,v1.0 + w,matrix_current_effect,05 + w,matrix_effect_none + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1chroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1chroma.cfg new file mode 100644 index 00000000..8c077b5f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1chroma.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0504.0001 +name = Razer Kraken 7.1 Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000504 + r,device_type,%(name)s + r,firmware_version,v1.0 + w,matrix_current_effect,05 + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1v2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1v2.cfg new file mode 100644 index 00000000..4473dcc1 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerkraken7.1v2.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0510.0001 +name = Razer Kraken 7.1 V2 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000510 + r,device_type,%(name)s + r,firmware_version,v1.0 + w,matrix_current_effect,05 + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerkrakenkittyedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerkrakenkittyedition.cfg new file mode 100644 index 00000000..d3aed475 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerkrakenkittyedition.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F19.0001 +name = Razer Kraken Kitty Edition +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F19 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerkrakenkittyv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerkrakenkittyv2.cfg new file mode 100644 index 00000000..1700f7c0 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerkrakenkittyv2.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0560.0001 +name = Razer Kraken Kitty V2 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000560 + r,device_type,%(name)s + r,firmware_version,v1.0 + w,matrix_current_effect,05 + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerkrakenultimate.cfg b/openrazer/pylib/openrazer/_fake_driver/razerkrakenultimate.cfg new file mode 100644 index 00000000..ead4d25a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerkrakenultimate.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0527.0001 +name = Razer Kraken Ultimate +files = rw,device_mode,0x0000 + r,device_serial,XX0000000527 + r,device_type,%(name)s + r,firmware_version,v1.0 + w,matrix_current_effect,05 + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerlanceheadtournamentedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadtournamentedition.cfg new file mode 100644 index 00000000..d5f2c520 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadtournamentedition.cfg @@ -0,0 +1,43 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0060.0001 +name = Razer Lancehead Tournament Edition +files = rw,device_mode,0x0000 + r,device_serial,XX0000000060 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,logo_matrix_effect_wave + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwired.cfg new file mode 100644 index 00000000..cf6773d1 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwired.cfg @@ -0,0 +1,47 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0059.0001 +name = Razer Lancehead (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000059 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,logo_matrix_effect_wave + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwireless.cfg new file mode 100644 index 00000000..6aecad22 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwireless.cfg @@ -0,0 +1,49 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:005A.0001 +name = Razer Lancehead (Wireless) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000005A + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,logo_matrix_effect_wave + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwirelessreceiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwirelessreceiver.cfg new file mode 100644 index 00000000..c3271ea8 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwirelessreceiver.cfg @@ -0,0 +1,49 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:006F.0001 +name = Razer Lancehead Wireless (Receiver) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000006F + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,logo_matrix_effect_wave + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwirelesswired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwirelesswired.cfg new file mode 100644 index 00000000..bd924dff --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerlanceheadwirelesswired.cfg @@ -0,0 +1,47 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0070.0001 +name = Razer Lancehead Wireless (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000070 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,logo_matrix_effect_wave + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerlaptopstandchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerlaptopstandchroma.cfg new file mode 100644 index 00000000..d4d6db69 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerlaptopstandchroma.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F0D.0001 +name = Razer Laptop Stand Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F0D + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerlaptopstandchromav2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerlaptopstandchromav2.cfg new file mode 100644 index 00000000..c7bc6716 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerlaptopstandchromav2.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F2B.0001 +name = Razer Laptop Stand Chroma V2 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F2B + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermamba2012wired.cfg b/openrazer/pylib/openrazer/_fake_driver/razermamba2012wired.cfg new file mode 100644 index 00000000..4fc243be --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermamba2012wired.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0024.0001 +name = Razer Mamba 2012 (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000024 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermamba2012wireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razermamba2012wireless.cfg new file mode 100644 index 00000000..e4696f6a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermamba2012wireless.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0025.0001 +name = Razer Mamba 2012 (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000025 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermambaelite.cfg b/openrazer/pylib/openrazer/_fake_driver/razermambaelite.cfg new file mode 100644 index 00000000..98fb8996 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermambaelite.cfg @@ -0,0 +1,45 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:006C.0001 +name = Razer Mamba Elite +files = rw,device_mode,0x0000 + r,device_serial,XX000000006C + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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,logo_matrix_effect_wave + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermambatournamentedition.cfg b/openrazer/pylib/openrazer/_fake_driver/razermambatournamentedition.cfg new file mode 100644 index 00000000..89c38d26 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermambatournamentedition.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0046.0001 +name = Razer Mamba Tournament Edition +files = rw,backlight_led_brightness,0 + w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_reactive + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + w,backlight_matrix_effect_wave + rw,device_mode,0x0000 + r,device_serial,XX0000000046 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,matrix_custom_frame + w,matrix_effect_custom + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermambawired.cfg b/openrazer/pylib/openrazer/_fake_driver/razermambawired.cfg new file mode 100644 index 00000000..bb4008b9 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermambawired.cfg @@ -0,0 +1,25 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0044.0001 +name = Razer Mamba (Wired) +files = w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_reactive + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + w,backlight_matrix_effect_wave + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000044 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermambawireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razermambawireless.cfg new file mode 100644 index 00000000..f0107bef --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermambawireless.cfg @@ -0,0 +1,27 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0045.0001 +name = Razer Mamba (Wireless) +files = w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_reactive + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + w,backlight_matrix_effect_wave + w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000045 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermambawirelessreceiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razermambawirelessreceiver.cfg new file mode 100644 index 00000000..be21ac6b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermambawirelessreceiver.cfg @@ -0,0 +1,32 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0072.0001 +name = Razer Mamba Wireless (Receiver) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000072 + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermambawirelesswired.cfg b/openrazer/pylib/openrazer/_fake_driver/razermambawirelesswired.cfg new file mode 100644 index 00000000..55204d36 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermambawirelesswired.cfg @@ -0,0 +1,30 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0073.0001 +name = Razer Mamba Wireless (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000073 + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermousebungeev3chroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razermousebungeev3chroma.cfg new file mode 100644 index 00000000..01fb1413 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermousebungeev3chroma.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F1D.0001 +name = Razer Mouse Bungee V3 Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F1D + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razermousedock.cfg b/openrazer/pylib/openrazer/_fake_driver/razermousedock.cfg new file mode 100644 index 00000000..df2d07c4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razermousedock.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:007E.0001 +name = Razer Mouse Dock +files = rw,device_mode,0x0000 + r,device_serial,XX000000007E + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernaga.cfg b/openrazer/pylib/openrazer/_fake_driver/razernaga.cfg new file mode 100644 index 00000000..a7bd967b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernaga.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0015.0001 +name = Razer Naga +files = w,backlight_matrix_effect_none + w,backlight_matrix_effect_on + rw,device_mode,0x0000 + r,device_serial,XX0000000015 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernaga2012.cfg b/openrazer/pylib/openrazer/_fake_driver/razernaga2012.cfg new file mode 100644 index 00000000..e49607dd --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernaga2012.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:002E.0001 +name = Razer Naga 2012 +files = w,backlight_matrix_effect_none + w,backlight_matrix_effect_on + rw,device_mode,0x0000 + r,device_serial,XX000000002E + r,device_type,%(name)s + rw,dpi,30:30 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernaga2014.cfg b/openrazer/pylib/openrazer/_fake_driver/razernaga2014.cfg new file mode 100644 index 00000000..55db16b4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernaga2014.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0040.0001 +name = Razer Naga 2014 +files = w,backlight_matrix_effect_none + w,backlight_matrix_effect_on + rw,device_mode,0x0000 + r,device_serial,XX0000000040 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + rw,tilt_hwheel,0 + rw,tilt_repeat,0 + rw,tilt_repeat_delay,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagachroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagachroma.cfg new file mode 100644 index 00000000..58554495 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagachroma.cfg @@ -0,0 +1,35 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0053.0001 +name = Razer Naga Chroma +files = rw,backlight_led_brightness,0 + w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_reactive + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + rw,device_mode,0x0000 + r,device_serial,XX0000000053 + 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/openrazer/pylib/openrazer/_fake_driver/razernagaepic.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagaepic.cfg new file mode 100644 index 00000000..7e4705bb --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagaepic.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:001F.0001 +name = Razer Naga Epic +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000001F + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagaepicchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagaepicchroma.cfg new file mode 100644 index 00000000..c95d376a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagaepicchroma.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:003E.0001 +name = Razer Naga Epic Chroma +files = rw,backlight_led_brightness,0 + w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000003E + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagaepicchromadock.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagaepicchromadock.cfg new file mode 100644 index 00000000..a145b511 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagaepicchromadock.cfg @@ -0,0 +1,26 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:003F.0001 +name = Razer Naga Epic Chroma Dock +files = rw,backlight_led_brightness,0 + w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000003F + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_breath + w,scroll_matrix_effect_none + w,scroll_matrix_effect_spectrum + w,scroll_matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagahex.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagahex.cfg new file mode 100644 index 00000000..1dfdc8df --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagahex.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0041.0001 +name = Razer Naga Hex +files = rw,device_mode,0x0000 + r,device_serial,XX0000000041 + r,device_type,%(name)s + rw,dpi,30:30 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagahexred.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagahexred.cfg new file mode 100644 index 00000000..6f29201e --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagahexred.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0036.0001 +name = Razer Naga Hex (Red) +files = rw,device_mode,0x0000 + r,device_serial,XX0000000036 + r,device_type,%(name)s + rw,dpi,30:30 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagahexv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagahexv2.cfg new file mode 100644 index 00000000..f004008c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagahexv2.cfg @@ -0,0 +1,32 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0050.0001 +name = Razer Naga Hex V2 +files = rw,backlight_led_brightness,0 + w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_reactive + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + rw,device_mode,0x0000 + r,device_serial,XX0000000050 + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagaleft-handededition2020.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagaleft-handededition2020.cfg new file mode 100644 index 00000000..92d30746 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagaleft-handededition2020.cfg @@ -0,0 +1,35 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:008D.0001 +name = Razer Naga Left-Handed Edition 2020 +files = rw,device_mode,0x0000 + r,device_serial,XX000000008D + 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,logo_matrix_effect_wave + w,matrix_custom_frame + w,matrix_effect_custom + rw,poll_rate,500 + rw,right_led_brightness,0 + w,right_matrix_effect_breath + w,right_matrix_effect_none + w,right_matrix_effect_reactive + w,right_matrix_effect_spectrum + w,right_matrix_effect_static + w,right_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagaprowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagaprowired.cfg new file mode 100644 index 00000000..9cea27d9 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagaprowired.cfg @@ -0,0 +1,39 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:008F.0001 +name = Razer Naga Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000008F + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagaprowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagaprowireless.cfg new file mode 100644 index 00000000..575b6033 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagaprowireless.cfg @@ -0,0 +1,41 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0090.0001 +name = Razer Naga Pro (Wireless) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000090 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagatrinity.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagatrinity.cfg new file mode 100644 index 00000000..99663dc0 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagatrinity.cfg @@ -0,0 +1,14 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0067.0001 +name = Razer Naga Trinity +files = rw,device_mode,0x0000 + r,device_serial,XX0000000067 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_effect_static + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagav2hyperspeedreceiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagav2hyperspeedreceiver.cfg new file mode 100644 index 00000000..44597cdb --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagav2hyperspeedreceiver.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B4.0001 +name = Razer Naga V2 HyperSpeed (Receiver) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000B4 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagav2prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagav2prowired.cfg new file mode 100644 index 00000000..bbccf1fc --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagav2prowired.cfg @@ -0,0 +1,32 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00A7.0001 +name = Razer Naga V2 Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000A7 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagav2prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagav2prowireless.cfg new file mode 100644 index 00000000..ce91c15f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagav2prowireless.cfg @@ -0,0 +1,34 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00A8.0001 +name = Razer Naga V2 Pro (Wireless) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000A8 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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,logo_matrix_effect_wave + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernagax.cfg b/openrazer/pylib/openrazer/_fake_driver/razernagax.cfg new file mode 100644 index 00000000..c09a4b38 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernagax.cfg @@ -0,0 +1,29 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0096.0001 +name = Razer Naga X +files = rw,device_mode,0x0000 + r,device_serial,XX0000000096 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,left_led_brightness,0 + w,left_matrix_effect_breath + w,left_matrix_effect_none + w,left_matrix_effect_reactive + w,left_matrix_effect_spectrum + w,left_matrix_effect_static + w,left_matrix_effect_wave + 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 + w,scroll_matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernommochroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razernommochroma.cfg new file mode 100644 index 00000000..2dc70443 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernommochroma.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0517.0001 +name = Razer Nommo Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000517 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernommopro.cfg b/openrazer/pylib/openrazer/_fake_driver/razernommopro.cfg new file mode 100644 index 00000000..d0da6d3b --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernommopro.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0518.0001 +name = Razer Nommo Pro +files = rw,device_mode,0x0000 + r,device_serial,XX0000000518 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razernostromo.cfg b/openrazer/pylib/openrazer/_fake_driver/razernostromo.cfg new file mode 100644 index 00000000..36588bb5 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razernostromo.cfg @@ -0,0 +1,15 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0111.0001 +name = Razer Nostromo +files = rw,device_mode,0x0000 + r,device_serial,XX0000000111 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + rw,profile_led_blue,0 + rw,profile_led_green,0 + rw,profile_led_red,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerorbweaver.cfg b/openrazer/pylib/openrazer/_fake_driver/razerorbweaver.cfg new file mode 100644 index 00000000..7badd978 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerorbweaver.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0113.0001 +name = Razer Orbweaver +files = rw,device_mode,0x0000 + r,device_serial,XX0000000113 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_none + w,matrix_effect_pulsate + w,matrix_effect_static + rw,profile_led_blue,0 + rw,profile_led_green,0 + rw,profile_led_red,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerorbweaverchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerorbweaverchroma.cfg new file mode 100644 index 00000000..4b94874d --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerorbweaverchroma.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0207.0001 +name = Razer Orbweaver Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000207 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,profile_led_blue,0 + rw,profile_led_green,0 + rw,profile_led_red,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornata.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornata.cfg new file mode 100644 index 00000000..10e60f49 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornata.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:021F.0001 +name = Razer Ornata +files = rw,device_mode,0x0000 + r,device_serial,XX000000021F + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornatachroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornatachroma.cfg new file mode 100644 index 00000000..3c9f4f73 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornatachroma.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:021E.0001 +name = Razer Ornata Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX000000021E + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornatav2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornatav2.cfg new file mode 100644 index 00000000..890abaf5 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornatav2.cfg @@ -0,0 +1,24 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:025D.0001 +name = Razer Ornata V2 +files = rw,device_mode,0x0000 + r,device_serial,XX000000025D + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornatav3.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornatav3.cfg new file mode 100644 index 00000000..b0b9cea5 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornatav3.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02A1.0001 +name = Razer Ornata V3 +files = rw,device_mode,0x0000 + r,device_serial,XX00000002A1 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornatav3_2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornatav3_2.cfg new file mode 100644 index 00000000..7c6e940e --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornatav3_2.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:028F.0001 +name = Razer Ornata V3 +files = rw,device_mode,0x0000 + r,device_serial,XX000000028F + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornatav3tenkeyless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornatav3tenkeyless.cfg new file mode 100644 index 00000000..f94d3f71 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornatav3tenkeyless.cfg @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02A3.0001 +name = Razer Ornata V3 Tenkeyless +files = rw,device_mode,0x0000 + r,device_serial,XX00000002A3 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornatav3x.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornatav3x.cfg new file mode 100644 index 00000000..e6fa1fe0 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornatav3x.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0294.0001 +name = Razer Ornata V3 X +files = rw,device_mode,0x0000 + r,device_serial,XX0000000294 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerornatav3x_2.cfg b/openrazer/pylib/openrazer/_fake_driver/razerornatav3x_2.cfg new file mode 100644 index 00000000..5f83f5fa --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerornatav3x_2.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:02A2.0001 +name = Razer Ornata V3 X +files = rw,device_mode,0x0000 + r,device_serial,XX00000002A2 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerorochi2011.cfg b/openrazer/pylib/openrazer/_fake_driver/razerorochi2011.cfg new file mode 100644 index 00000000..3c60d28e --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerorochi2011.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0013.0001 +name = Razer Orochi 2011 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000013 + r,device_type,%(name)s + rw,dpi,30:30 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerorochi2013.cfg b/openrazer/pylib/openrazer/_fake_driver/razerorochi2013.cfg new file mode 100644 index 00000000..c0a95778 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerorochi2013.cfg @@ -0,0 +1,14 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0039.0001 +name = Razer Orochi 2013 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000039 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerorochiv2bluetooth.cfg b/openrazer/pylib/openrazer/_fake_driver/razerorochiv2bluetooth.cfg new file mode 100644 index 00000000..345d6a42 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerorochiv2bluetooth.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0095.0001 +name = Razer Orochi V2 (Bluetooth) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000095 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerorochiv2receiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razerorochiv2receiver.cfg new file mode 100644 index 00000000..3bc37363 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerorochiv2receiver.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0094.0001 +name = Razer Orochi V2 (Receiver) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000094 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerorochiwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerorochiwired.cfg new file mode 100644 index 00000000..e49f02b3 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerorochiwired.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0048.0001 +name = Razer Orochi (Wired) +files = w,backlight_matrix_effect_breath + w,backlight_matrix_effect_none + w,backlight_matrix_effect_reactive + w,backlight_matrix_effect_spectrum + w,backlight_matrix_effect_static + rw,charge_low_threshold,38 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000048 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerouroboros.cfg b/openrazer/pylib/openrazer/_fake_driver/razerouroboros.cfg new file mode 100644 index 00000000..7ba3268c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerouroboros.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0032.0001 +name = Razer Ouroboros +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000032 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + rw,poll_rate,500 + rw,scroll_led_brightness,0 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerproclickminireceiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razerproclickminireceiver.cfg new file mode 100644 index 00000000..c106bcd9 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerproclickminireceiver.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:009A.0001 +name = Razer Pro Click Mini (Receiver) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000009A + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerproclickreceiver.cfg b/openrazer/pylib/openrazer/_fake_driver/razerproclickreceiver.cfg new file mode 100644 index 00000000..b384246f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerproclickreceiver.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0077.0001 +name = Razer Pro Click (Receiver) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000077 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerproclickv2verticaleditionwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerproclickv2verticaleditionwired.cfg new file mode 100644 index 00000000..97dda417 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerproclickv2verticaleditionwired.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C7.0001 +name = Razer Pro Click V2 Vertical Edition (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C7 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerproclickv2verticaleditionwireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerproclickv2verticaleditionwireless.cfg new file mode 100644 index 00000000..270aa395 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerproclickv2verticaleditionwireless.cfg @@ -0,0 +1,22 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C8.0001 +name = Razer Pro Click V2 Vertical Edition (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C8 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerproclickwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerproclickwired.cfg new file mode 100644 index 00000000..cb47c34c --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerproclickwired.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0080.0001 +name = Razer Pro Click (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX0000000080 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerraptor27.cfg b/openrazer/pylib/openrazer/_fake_driver/razerraptor27.cfg new file mode 100644 index 00000000..7b74c7c0 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerraptor27.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F12.0001 +name = Razer Raptor 27 +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F12 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerstriderchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerstriderchroma.cfg new file mode 100644 index 00000000..73b9ea39 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerstriderchroma.cfg @@ -0,0 +1,20 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0C05.0001 +name = Razer Strider Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000C05 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_static + w,matrix_effect_wave + w,matrix_reactive_trigger + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razertaipan.cfg b/openrazer/pylib/openrazer/_fake_driver/razertaipan.cfg new file mode 100644 index 00000000..4e27a07e --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razertaipan.cfg @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0034.0001 +name = Razer Taipan +files = rw,device_mode,0x0000 + r,device_serial,XX0000000034 + r,device_type,%(name)s + rw,dpi,800:800 + r,firmware_version,v1.0 + w,logo_matrix_effect_none + w,logo_matrix_effect_on + rw,poll_rate,500 + w,scroll_matrix_effect_none + w,scroll_matrix_effect_on + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razertartarus.cfg b/openrazer/pylib/openrazer/_fake_driver/razertartarus.cfg new file mode 100644 index 00000000..afae37cf --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razertartarus.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0201.0001 +name = Razer Tartarus +files = rw,device_mode,0x0000 + r,device_serial,XX0000000201 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_pulsate + w,matrix_effect_static + rw,profile_led_blue,0 + rw,profile_led_green,0 + rw,profile_led_red,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razertartaruschroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razertartaruschroma.cfg new file mode 100644 index 00000000..415b25d4 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razertartaruschroma.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0208.0001 +name = Razer Tartarus Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000208 + r,device_type,%(name)s + r,firmware_version,v1.0 + r,kbd_layout,01 + rw,matrix_brightness,0 + w,matrix_effect_breath + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_static + rw,profile_led_blue,0 + rw,profile_led_green,0 + rw,profile_led_red,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razertartarusv2.cfg b/openrazer/pylib/openrazer/_fake_driver/razertartarusv2.cfg new file mode 100644 index 00000000..2b244060 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razertartarusv2.cfg @@ -0,0 +1,27 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:022B.0001 +name = Razer Tartarus V2 +files = rw,device_mode,0x0000 + r,device_serial,XX000000022B + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,game_led_state,0 + r,kbd_layout,01 + rw,macro_led_effect,0 + rw,macro_led_state,0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_reactive + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + rw,profile_led_blue,0 + rw,profile_led_green,0 + rw,profile_led_red,0 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerthunderbolt4dockchroma.cfg b/openrazer/pylib/openrazer/_fake_driver/razerthunderbolt4dockchroma.cfg new file mode 100644 index 00000000..e77f660a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerthunderbolt4dockchroma.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0F21.0001 +name = Razer Thunderbolt 4 Dock Chroma +files = rw,device_mode,0x0000 + r,device_serial,XX0000000F21 + r,device_type,%(name)s + r,firmware_version,v1.0 + rw,matrix_brightness,0 + w,matrix_custom_frame + w,matrix_effect_breath + w,matrix_effect_custom + w,matrix_effect_none + w,matrix_effect_spectrum + w,matrix_effect_starlight + w,matrix_effect_static + w,matrix_effect_wave + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviper.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviper.cfg new file mode 100644 index 00000000..60a6bc56 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviper.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0078.0001 +name = Razer Viper +files = rw,device_mode,0x0000 + r,device_serial,XX0000000078 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviper8khz.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviper8khz.cfg new file mode 100644 index 00000000..dfdb21a0 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviper8khz.cfg @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:0091.0001 +name = Razer Viper 8KHz +files = rw,device_mode,0x0000 + r,device_serial,XX0000000091 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razervipermini.cfg b/openrazer/pylib/openrazer/_fake_driver/razervipermini.cfg new file mode 100644 index 00000000..d9d898f7 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razervipermini.cfg @@ -0,0 +1,21 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:008A.0001 +name = Razer Viper Mini +files = rw,device_mode,0x0000 + r,device_serial,XX000000008A + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperminisignatureeditionwired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperminisignatureeditionwired.cfg new file mode 100644 index 00000000..eaca496f --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperminisignatureeditionwired.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:009E.0001 +name = Razer Viper Mini Signature Edition (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000009E + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperminisignatureeditionwireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperminisignatureeditionwireless.cfg new file mode 100644 index 00000000..bfc4accc --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperminisignatureeditionwireless.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:009F.0001 +name = Razer Viper Mini Signature Edition (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000009F + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + w,hyperpolling_wireless_dongle_indicator_led_mode + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperultimatewired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperultimatewired.cfg new file mode 100644 index 00000000..a4ca194a --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperultimatewired.cfg @@ -0,0 +1,25 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:007A.0001 +name = Razer Viper Ultimate (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000007A + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperultimatewireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperultimatewireless.cfg new file mode 100644 index 00000000..ed0bc804 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperultimatewireless.cfg @@ -0,0 +1,27 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:007B.0001 +name = Razer Viper Ultimate (Wireless) +files = w,charge_colour + w,charge_effect + r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX000000007B + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + 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 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperv2prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperv2prowired.cfg new file mode 100644 index 00000000..da4c3817 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperv2prowired.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00A5.0001 +name = Razer Viper V2 Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000A5 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperv2prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperv2prowireless.cfg new file mode 100644 index 00000000..ac48b992 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperv2prowireless.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00A6.0001 +name = Razer Viper V2 Pro (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000A6 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperv3hyperspeed.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperv3hyperspeed.cfg new file mode 100644 index 00000000..53f09757 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperv3hyperspeed.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00B8.0001 +name = Razer Viper V3 HyperSpeed +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000B8 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperv3prowired.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperv3prowired.cfg new file mode 100644 index 00000000..e2576e77 --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperv3prowired.cfg @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C0.0001 +name = Razer Viper V3 Pro (Wired) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C0 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/_fake_driver/razerviperv3prowireless.cfg b/openrazer/pylib/openrazer/_fake_driver/razerviperv3prowireless.cfg new file mode 100644 index 00000000..5514e2ca --- /dev/null +++ b/openrazer/pylib/openrazer/_fake_driver/razerviperv3prowireless.cfg @@ -0,0 +1,18 @@ +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:00C1.0001 +name = Razer Viper V3 Pro (Wireless) +files = r,charge_level,255 + rw,charge_low_threshold,38 + r,charge_status,1 + rw,device_idle_time,600 + rw,device_mode,0x0000 + r,device_serial,XX00000000C1 + r,device_type,%(name)s + rw,dpi,800:800 + rw,dpi_stages,0x010320032005dc05dc + r,firmware_version,v1.0 + w,hyperpolling_wireless_dongle_indicator_led_mode + rw,poll_rate,500 + r,version,1.0.0 diff --git a/openrazer/pylib/openrazer/client/__init__.py b/openrazer/pylib/openrazer/client/__init__.py new file mode 100644 index 00000000..fd82c8af --- /dev/null +++ b/openrazer/pylib/openrazer/client/__init__.py @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import json +import dbus as _dbus +from openrazer.client.device import RazerDeviceFactory as _RazerDeviceFactory +from openrazer.client import constants + +__version__ = '3.10.3' + + +class DaemonNotFound(Exception): + pass + + +class DeviceManager(object): + """ + DeviceManager Class + """ + + def __init__(self): + # Load up the DBus + session_bus = _dbus.SessionBus() + try: + self._dbus = session_bus.get_object("org.razer", "/org/razer") + except _dbus.DBusException: + raise DaemonNotFound("Could not connect to daemon") + + # Get interface for daemon methods + self._dbus_daemon = _dbus.Interface(self._dbus, "razer.daemon") + + # Get interface for devices methods + self._dbus_devices = _dbus.Interface(self._dbus, "razer.devices") + + self._device_serials = self._dbus_devices.getDevices() + self._devices = [] + + self._daemon_version = self._dbus_daemon.version() + + for serial in self._device_serials: + device = _RazerDeviceFactory.get_device(serial) + self._devices.append(device) + + def stop_daemon(self): + """ + Stops the Daemon via a DBus call + """ + self._dbus_daemon.stop() + + @property + def turn_off_on_screensaver(self): + return self._dbus_devices.getOffOnScreensaver() + + @turn_off_on_screensaver.setter + def turn_off_on_screensaver(self, enable): + """ + Enable or Disable the logic to turn off the devices whilst the screensaver is active + + If True, when the screensaver is active the devices' brightness will be set to 0. + When the screensaver is inactive the devices' brightness will be restored + :param enable: True to enable screensaver disable + :type enable: bool + + :raises ValueError: If enable isn't a bool + """ + if not isinstance(enable, bool): + raise ValueError("Enable must be a boolean") + + self._dbus_devices.enableTurnOffOnScreensaver(enable) + + @property + def sync_effects(self): + return self._dbus_devices.getSyncEffects() + + @sync_effects.setter + def sync_effects(self, sync): + """ + Enable or disable the syncing of effects between devices + + If sync is enabled, whenever an effect is set then it will be set on all other devices if the effect is available or a similar effect if it is not. + + :param sync: Sync effects + :type sync: bool + + :raises ValueError: If sync isn't a bool + """ + if not isinstance(sync, bool): + raise ValueError("Sync must be a boolean") + + self._dbus_devices.syncEffects(sync) + + @property + def supported_devices(self): + json_data = self._dbus_daemon.supportedDevices() + + return json.loads(json_data) + + @property + def devices(self): + """ + A list of Razer devices + + :return: List of devices + :rtype: list[razer.client.devices.RazerDevice] + """ + + return self._devices + + @property + def version(self): + """ + Python library version + + :return: Version + :rtype: str + """ + return __version__ + + @property + def daemon_version(self): + """ + Daemon version + + :return: Daemon version + :rtype: str + """ + return str(self._daemon_version) + + +if __name__ == '__main__': + a = DeviceManager() + b = a.devices[0] + + print() diff --git a/openrazer/pylib/openrazer/client/constants.py b/openrazer/pylib/openrazer/client/constants.py new file mode 100644 index 00000000..67f5628f --- /dev/null +++ b/openrazer/pylib/openrazer/client/constants.py @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Macro LED effect ID's +MACRO_LED_STATIC = 0x00 +MACRO_LED_BLINK = 0x01 + +# Wave Directions +WAVE_RIGHT = 0x01 +WAVE_LEFT = 0x02 + +# Wheel directions +WHEEL_RIGHT = 0x01 +WHEEL_LEFT = 0x02 + +# Reactive +REACTIVE_500MS = 0x01 +REACTIVE_1000MS = 0x02 +REACTIVE_1500MS = 0x03 +REACTIVE_2000MS = 0x04 + +# Starlight +STARLIGHT_FAST = 0x01 +STARLIGHT_NORMAL = 0x02 +STARLIGHT_SLOW = 0x03 + +# Ripple +RIPPLE_REFRESH_RATE = 0.05 + +# NOTE: These constants are deprecated. Use values from supported_poll_rates instead +POLL_8000HZ = 8000 +POLL_4000HZ = 4000 +POLL_2000HZ = 2000 +POLL_1000HZ = 1000 +POLL_500HZ = 500 +POLL_250HZ = 250 +POLL_125HZ = 125 diff --git a/openrazer/pylib/openrazer/client/debug.py b/openrazer/pylib/openrazer/client/debug.py new file mode 100644 index 00000000..ff98553a --- /dev/null +++ b/openrazer/pylib/openrazer/client/debug.py @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import types +import inspect + + +def get_attrs(obj): + all_obj_attrs = [x for x in dir(obj) if not x.startswith('_')] + props = [] + funcs = [] + fields = [] + + for obj_attr in all_obj_attrs: + objs_to_check = list(obj.__class__.__mro__) + objs_to_check.insert(0, obj) + + for obj_class in objs_to_check: + try: + attr = getattr(obj_class, obj_attr) + + if isinstance(attr, property): + get_sig = str(inspect.signature(attr.fget)) + if '->' in get_sig: + get_sig = ':' + get_sig.split('-> ')[1] + else: + get_sig = '' + + if attr.fset is not None: + set_sig = inspect.signature(attr.fset) + if len(set_sig.parameters.keys()) > 0: + set_type = str(set_sig.parameters[list(set_sig.parameters.keys())[-1]]) + else: + set_type = '' + + if ':' in set_type: + set_type = ':' + set_type.split(':')[1] + else: + set_type = '' + props.append(obj_attr + ' - get{0}, set{1}'.format(get_sig, set_type)) + else: + props.append(obj_attr + ' - get{0}'.format(get_sig)) + break + elif isinstance(attr, types.FunctionType): + funcs.append(obj_attr + str(inspect.signature(attr))) + break + except Exception as err: + pass + else: + fields.append(obj_attr) + + return sorted(props), sorted(funcs), sorted(fields) + + +def print_attrs(obj, recurse_to=None, indent=0): + if recurse_to is None: + recurse_to = set() + else: + recurse_to = set(recurse_to) + + props, funcs, fields = get_attrs(obj) + + def print2(x): return print((" " * indent) + x) + + print(obj.__class__.__name__) + if len(props) > 0: + if len(funcs) + len(fields) == 0: + print2(" └ properties:") + pipe = ' ' + else: + print2(" ├ properties:") + pipe = '│' + + for index, prop in enumerate(props, start=1): + if prop in recurse_to: + if len(props) != index: + print((" " * indent) + ' {0} ├- {1} - '.format(pipe, prop), end='') + print_attrs(getattr(obj, prop), recurse_to=(recurse_to - set(prop)), indent=indent + 7) + else: + print((" " * indent) + ' {0} └- {1} - '.format(pipe, prop), end='') + print_attrs(getattr(obj, prop), recurse_to=(recurse_to - set(prop)), indent=indent + 7) + else: + if len(props) != index: + print2(' {0} ├- {1}'.format(pipe, prop)) + else: + print2(' {0} └- {1}'.format(pipe, prop)) + if len(funcs) > 0: + if len(fields) == 0: + print2(" └ methods:") + pipe = ' ' + else: + print2(" ├ methods:") + pipe = '│' + + for index, func in enumerate(funcs, start=1): + if len(funcs) != index: + print2(' {0} ├- {1}'.format(pipe, func)) + else: + print2(' {0} └- {1}'.format(pipe, func)) + if len(fields) > 0: + print2(" └ fields:") + + for index, field in enumerate(fields, start=1): + if field in recurse_to: + if len(fields) != index: + print((" " * indent) + ' ├- {0} - '.format(field), end='') + print_attrs(getattr(obj, field), recurse_to=(recurse_to - set(field)), indent=indent + 6) + else: + print((" " * indent) + ' └- {0} - '.format(field), end='') + print_attrs(getattr(obj, field), recurse_to=(recurse_to - set(field)), indent=indent + 6) + else: + if len(fields) != index: + print2(' ├- {0}'.format(field)) + else: + print2(' └- {0}'.format(field)) diff --git a/openrazer/pylib/openrazer/client/device.py b/openrazer/pylib/openrazer/client/device.py new file mode 100644 index 00000000..1388e31a --- /dev/null +++ b/openrazer/pylib/openrazer/client/device.py @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import dbus as _dbus +from openrazer.client.devices import RazerDevice as __RazerDevice, BaseDeviceFactory as __BaseDeviceFactory +from openrazer.client.devices.mousemat import RazerMousemat as __RazerMousemat +from openrazer.client.devices.keyboard import RazerKeyboardFactory as __RazerKeyboardFactory +from openrazer.client.devices.mice import RazerMouse as __RazerMouse + + +DEVICE_MAP = { + 'mousemat': __RazerMousemat, + 'keyboard': __RazerKeyboardFactory, + 'mouse': __RazerMouse, + 'keypad': __RazerKeyboardFactory, + 'default': __RazerDevice +} + + +class RazerDeviceFactory(__BaseDeviceFactory): + """ + Simple factory to return an object for a given device + + """ + @staticmethod + def get_device(serial, vid_pid=None, daemon_dbus=None): + """ + Factory for turning a serial into a class + + Device factory, will return a class fit for the device in question. The DEVICE_MAP mapping above + can contain a device_type => DeviceClass or DeviceFactory, this allows us to specify raw device classes + if there is only one model (like Firefly) or a factory for the keyboards (so we can differentiate between + old blackwidows and chromas). If the device is not in the device mapping then the factory will default + to a raw RazerDevice. + + :param serial: Device serial + :type serial: str + + :param vid_pid: Device VID, PID + :type vid_pid: list of int + + :param daemon_dbus: Daemon DBus object + :type daemon_dbus: object or None + + :return: RazerDevice object (or subclass) + :rtype: RazerDevice + """ + if daemon_dbus is None: + session_bus = _dbus.SessionBus() + daemon_dbus = session_bus.get_object("org.razer", "/org/razer/device/{0}".format(serial)) + + device_dbus = _dbus.Interface(daemon_dbus, "razer.device.misc") + + device_type = device_dbus.getDeviceType() + device_vid_pid = device_dbus.getVidPid() + + if device_type in DEVICE_MAP: + # Have device mapping + device_class = DEVICE_MAP[device_type] + if hasattr(device_class, 'get_device'): + # DeviceFactory + device = device_class.get_device(serial, vid_pid=device_vid_pid, daemon_dbus=daemon_dbus) + else: + # DeviceClass + device = device_class(serial, vid_pid=device_vid_pid, daemon_dbus=daemon_dbus) + else: + # No mapping, default to RazerDevice + device = DEVICE_MAP['default'](serial, vid_pid=device_vid_pid, daemon_dbus=daemon_dbus) + + return device diff --git a/openrazer/pylib/openrazer/client/devices/__init__.py b/openrazer/pylib/openrazer/client/devices/__init__.py new file mode 100644 index 00000000..a0d63f3f --- /dev/null +++ b/openrazer/pylib/openrazer/client/devices/__init__.py @@ -0,0 +1,581 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import json +import dbus as _dbus +from openrazer.client.fx import RazerFX as _RazerFX +from xml.etree import ElementTree as _ET +from openrazer.client.macro import RazerMacro as _RazerMacro +from openrazer.client import constants as _c + + +class RazerDevice(object): + """ + Raw razer base device + """ + _FX = _RazerFX + _MACRO_CLASS = _RazerMacro + + def __init__(self, serial, vid_pid=None, daemon_dbus=None): + # Load up the DBus + if daemon_dbus is None: + session_bus = _dbus.SessionBus() + daemon_dbus = session_bus.get_object("org.razer", "/org/razer/device/{0}".format(serial)) + + self._dbus = daemon_dbus + + self._available_features = self._get_available_features() + + self._dbus_interfaces = { + 'device': _dbus.Interface(self._dbus, "razer.device.misc"), + 'brightness': _dbus.Interface(self._dbus, "razer.device.lighting.brightness") + } + + self._name = str(self._dbus_interfaces['device'].getDeviceName()) + self._type = str(self._dbus_interfaces['device'].getDeviceType()) + self._fw = str(self._dbus_interfaces['device'].getFirmware()) + self._drv_version = str(self._dbus_interfaces['device'].getDriverVersion()) + self._has_dedicated_macro = None + self._device_image = None + + # Deprecated API, but kept for backwards compatibility + self._urls = None + + if vid_pid is None: + self._vid, self._pid = self._dbus_interfaces['device'].getVidPid() + else: + self._vid, self._pid = vid_pid + + self._serial = serial + + self._capabilities = { + 'name': True, + 'type': True, + 'firmware_version': True, + 'serial': True, + 'brightness': self._has_feature('razer.device.lighting.brightness'), + + 'battery': self._has_feature('razer.device.power', 'getBattery'), + 'idle_time': self._has_feature('razer.device.power', ('getIdleTime', 'setIdleTime')), + 'low_battery_threshold': self._has_feature('razer.device.power', ('getLowBatteryThreshold', 'setLowBatteryThreshold')), + # Deprecated, use idle_time & low_battery_threshold + 'get_idle_time': self._has_feature('razer.device.power', 'getIdleTime'), + 'set_idle_time': self._has_feature('razer.device.power', 'setIdleTime'), + 'get_low_battery_threshold': self._has_feature('razer.device.power', 'getLowBatteryThreshold'), + 'set_low_battery_threshold': self._has_feature('razer.device.power', 'setLowBatteryThreshold'), + + 'macro_logic': self._has_feature('razer.device.macro'), + 'keyboard_layout': self._has_feature('razer.device.misc', 'getKeyboardLayout'), + 'game_mode_led': self._has_feature('razer.device.led.gamemode'), + 'keyswitch_optimization': self._has_feature('razer.device.misc.keyswitchoptimization', ('getKeyswitchOptimization', 'setKeyswitchOptimization')), + 'macro_mode_led': self._has_feature('razer.device.led.macromode', 'setMacroMode'), + 'macro_mode_led_effect': self._has_feature('razer.device.led.macromode', 'setMacroEffect'), + 'macro_mode_modifier': self._has_feature('razer.device.macro', 'setModeModifier'), + 'reactive_trigger': self._has_feature('razer.device.misc', 'triggerReactive'), + + 'poll_rate': self._has_feature('razer.device.misc', ('getPollRate', 'setPollRate')), + 'supported_poll_rates': self._has_feature('razer.device.misc', 'getSupportedPollRates'), + 'dpi': self._has_feature('razer.device.dpi', ('getDPI', 'setDPI')), + 'dpi_stages': self._has_feature('razer.device.dpi', ('getDPIStages', 'setDPIStages')), + 'available_dpi': self._has_feature('razer.device.dpi', 'availableDPI'), + 'scroll_mode': self._has_feature('razer.device.scroll', ('getScrollMode', 'setScrollMode')), + 'scroll_acceleration': self._has_feature('razer.device.scroll', ('getScrollAcceleration', 'setScrollAcceleration')), + 'scroll_smart_reel': self._has_feature('razer.device.scroll', ('getScrollSmartReel', 'setScrollSmartReel')), + + # Default device is a chroma so lighting capabilities + 'lighting': self._has_feature('razer.device.lighting.chroma'), + 'lighting_breath_single': self._has_feature('razer.device.lighting.chroma', 'setBreathSingle'), + 'lighting_breath_dual': self._has_feature('razer.device.lighting.chroma', 'setBreathDual'), + 'lighting_breath_triple': self._has_feature('razer.device.lighting.chroma', 'setBreathTriple'), + 'lighting_breath_random': self._has_feature('razer.device.lighting.chroma', 'setBreathRandom'), + 'lighting_wave': self._has_feature('razer.device.lighting.chroma', 'setWave'), + 'lighting_wheel': self._has_feature('razer.device.lighting.chroma', 'setWheel'), + 'lighting_reactive': self._has_feature('razer.device.lighting.chroma', 'setReactive'), + 'lighting_none': self._has_feature('razer.device.lighting.chroma', 'setNone'), + 'lighting_spectrum': self._has_feature('razer.device.lighting.chroma', 'setSpectrum'), + 'lighting_static': self._has_feature('razer.device.lighting.chroma', 'setStatic'), + 'lighting_blinking': self._has_feature('razer.device.lighting.chroma', 'setBlinking'), + + 'lighting_starlight_single': self._has_feature('razer.device.lighting.chroma', 'setStarlightSingle'), + 'lighting_starlight_dual': self._has_feature('razer.device.lighting.chroma', 'setStarlightDual'), + 'lighting_starlight_random': self._has_feature('razer.device.lighting.chroma', 'setStarlightRandom'), + + 'lighting_ripple': self._has_feature('razer.device.lighting.custom', 'setRipple'), # Thinking of extending custom to do more hence the key check + 'lighting_ripple_random': self._has_feature('razer.device.lighting.custom', 'setRippleRandomColour'), + + 'lighting_pulsate': self._has_feature('razer.device.lighting.bw2013', 'setPulsate'), + + # Get if the device has an LED Matrix, == True as its a DBus boolean otherwise, so for consistency sake we coerce it into a native bool + 'lighting_led_matrix': self._dbus_interfaces['device'].hasMatrix() == True, + 'lighting_led_single': self._has_feature('razer.device.lighting.chroma', 'setKey'), + + # Mouse lighting attrs + 'lighting_logo': self._has_feature('razer.device.lighting.logo'), + 'lighting_logo_active': self._has_feature('razer.device.lighting.logo', 'setLogoActive'), + 'lighting_logo_blinking': self._has_feature('razer.device.lighting.logo', 'setLogoBlinking'), + 'lighting_logo_brightness': self._has_feature('razer.device.lighting.logo', 'setLogoBrightness'), + 'lighting_logo_pulsate': self._has_feature('razer.device.lighting.logo', 'setLogoPulsate'), + 'lighting_logo_spectrum': self._has_feature('razer.device.lighting.logo', 'setLogoSpectrum'), + 'lighting_logo_static': self._has_feature('razer.device.lighting.logo', 'setLogoStatic'), + 'lighting_logo_none': self._has_feature('razer.device.lighting.logo', 'setLogoNone'), + 'lighting_logo_on': self._has_feature('razer.device.lighting.logo', 'setLogoOn'), + 'lighting_logo_reactive': self._has_feature('razer.device.lighting.logo', 'setLogoReactive'), + 'lighting_logo_wave': self._has_feature('razer.device.lighting.logo', 'setLogoWave'), + 'lighting_logo_breath_single': self._has_feature('razer.device.lighting.logo', 'setLogoBreathSingle'), + 'lighting_logo_breath_dual': self._has_feature('razer.device.lighting.logo', 'setLogoBreathDual'), + 'lighting_logo_breath_random': self._has_feature('razer.device.lighting.logo', 'setLogoBreathRandom'), + 'lighting_logo_breath_mono': self._has_feature('razer.device.lighting.logo', 'setLogoBreathMono'), + + 'lighting_scroll': self._has_feature('razer.device.lighting.scroll'), + 'lighting_scroll_active': self._has_feature('razer.device.lighting.scroll', 'setScrollActive'), + 'lighting_scroll_blinking': self._has_feature('razer.device.lighting.scroll', 'setScrollBlinking'), + 'lighting_scroll_brightness': self._has_feature('razer.device.lighting.scroll', 'setScrollBrightness'), + 'lighting_scroll_pulsate': self._has_feature('razer.device.lighting.scroll', 'setScrollPulsate'), + 'lighting_scroll_spectrum': self._has_feature('razer.device.lighting.scroll', 'setScrollSpectrum'), + 'lighting_scroll_static': self._has_feature('razer.device.lighting.scroll', 'setScrollStatic'), + 'lighting_scroll_none': self._has_feature('razer.device.lighting.scroll', 'setScrollNone'), + 'lighting_scroll_on': self._has_feature('razer.device.lighting.scroll', 'setScrollOn'), + 'lighting_scroll_reactive': self._has_feature('razer.device.lighting.scroll', 'setScrollReactive'), + 'lighting_scroll_wave': self._has_feature('razer.device.lighting.scroll', 'setScrollWave'), + 'lighting_scroll_breath_single': self._has_feature('razer.device.lighting.scroll', 'setScrollBreathSingle'), + 'lighting_scroll_breath_dual': self._has_feature('razer.device.lighting.scroll', 'setScrollBreathDual'), + 'lighting_scroll_breath_random': self._has_feature('razer.device.lighting.scroll', 'setScrollBreathRandom'), + 'lighting_scroll_breath_mono': self._has_feature('razer.device.lighting.scroll', 'setScrollBreathMono'), + + 'lighting_left': self._has_feature('razer.device.lighting.left'), + 'lighting_left_active': self._has_feature('razer.device.lighting.left', 'setLeftActive'), + 'lighting_left_brightness': self._has_feature('razer.device.lighting.left', 'setLeftBrightness'), + 'lighting_left_spectrum': self._has_feature('razer.device.lighting.left', 'setLeftSpectrum'), + 'lighting_left_static': self._has_feature('razer.device.lighting.left', 'setLeftStatic'), + 'lighting_left_none': self._has_feature('razer.device.lighting.left', 'setLeftNone'), + 'lighting_left_reactive': self._has_feature('razer.device.lighting.left', 'setLeftReactive'), + 'lighting_left_wave': self._has_feature('razer.device.lighting.left', 'setLeftWave'), + 'lighting_left_breath_single': self._has_feature('razer.device.lighting.left', 'setLeftBreathSingle'), + 'lighting_left_breath_dual': self._has_feature('razer.device.lighting.left', 'setLeftBreathDual'), + 'lighting_left_breath_random': self._has_feature('razer.device.lighting.left', 'setLeftBreathRandom'), + 'lighting_left_breath_mono': self._has_feature('razer.device.lighting.left', 'setLeftBreathMono'), + + 'lighting_right': self._has_feature('razer.device.lighting.right'), + 'lighting_right_active': self._has_feature('razer.device.lighting.right', 'setRightActive'), + 'lighting_right_brightness': self._has_feature('razer.device.lighting.right', 'setRightBrightness'), + 'lighting_right_spectrum': self._has_feature('razer.device.lighting.right', 'setRightSpectrum'), + 'lighting_right_static': self._has_feature('razer.device.lighting.right', 'setRightStatic'), + 'lighting_right_none': self._has_feature('razer.device.lighting.right', 'setRightNone'), + 'lighting_right_reactive': self._has_feature('razer.device.lighting.right', 'setRightReactive'), + 'lighting_right_wave': self._has_feature('razer.device.lighting.right', 'setRightWave'), + 'lighting_right_breath_single': self._has_feature('razer.device.lighting.right', 'setRightBreathSingle'), + 'lighting_right_breath_dual': self._has_feature('razer.device.lighting.right', 'setRightBreathDual'), + 'lighting_right_breath_random': self._has_feature('razer.device.lighting.right', 'setRightBreathRandom'), + 'lighting_right_breath_mono': self._has_feature('razer.device.lighting.right', 'setRightBreathMono'), + + 'lighting_backlight': self._has_feature('razer.device.lighting.backlight'), + 'lighting_backlight_active': self._has_feature('razer.device.lighting.backlight', 'setBacklightActive'), + 'lighting_backlight_brightness': self._has_feature('razer.device.lighting.backlight', 'setBacklightBrightness'), + 'lighting_backlight_spectrum': self._has_feature('razer.device.lighting.backlight', 'setBacklightSpectrum'), + 'lighting_backlight_static': self._has_feature('razer.device.lighting.backlight', 'setBacklightStatic'), + 'lighting_backlight_none': self._has_feature('razer.device.lighting.backlight', 'setBacklightNone'), + 'lighting_backlight_on': self._has_feature('razer.device.lighting.backlight', 'setBacklightOn'), + 'lighting_backlight_reactive': self._has_feature('razer.device.lighting.backlight', 'setBacklightReactive'), + 'lighting_backlight_wave': self._has_feature('razer.device.lighting.backlight', 'setBacklightWave'), + 'lighting_backlight_breath_single': self._has_feature('razer.device.lighting.backlight', 'setBacklightBreathSingle'), + 'lighting_backlight_breath_dual': self._has_feature('razer.device.lighting.backlight', 'setBacklightBreathDual'), + 'lighting_backlight_breath_random': self._has_feature('razer.device.lighting.backlight', 'setBacklightBreathRandom'), + 'lighting_backlight_breath_mono': self._has_feature('razer.device.lighting.backlight', 'setBacklightBreathMono'), + + 'lighting_profile_led_red': self._has_feature('razer.device.lighting.profile_led', 'setRedLED'), + 'lighting_profile_led_green': self._has_feature('razer.device.lighting.profile_led', 'setGreenLED'), + 'lighting_profile_led_blue': self._has_feature('razer.device.lighting.profile_led', 'setBlueLED'), + + # Charging Pad attrs + 'lighting_charging': self._has_feature('razer.device.lighting.charging'), + 'lighting_charging_active': self._has_feature('razer.device.lighting.charging', 'setChargingActive'), + 'lighting_charging_brightness': self._has_feature('razer.device.lighting.charging', 'setChargingBrightness'), + 'lighting_charging_spectrum': self._has_feature('razer.device.lighting.charging', 'setChargingSpectrum'), + 'lighting_charging_static': self._has_feature('razer.device.lighting.charging', 'setChargingStatic'), + 'lighting_charging_none': self._has_feature('razer.device.lighting.charging', 'setChargingNone'), + 'lighting_charging_wave': self._has_feature('razer.device.lighting.charging', 'setChargingWave'), + 'lighting_charging_breath_single': self._has_feature('razer.device.lighting.charging', 'setChargingBreathSingle'), + 'lighting_charging_breath_dual': self._has_feature('razer.device.lighting.charging', 'setChargingBreathDual'), + 'lighting_charging_breath_random': self._has_feature('razer.device.lighting.charging', 'setChargingBreathRandom'), + 'lighting_charging_breath_mono': self._has_feature('razer.device.lighting.charging', 'setChargingBreathMono'), + + 'lighting_fast_charging': self._has_feature('razer.device.lighting.fast_charging'), + 'lighting_fast_charging_active': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingActive'), + 'lighting_fast_charging_brightness': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingBrightness'), + 'lighting_fast_charging_spectrum': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingSpectrum'), + 'lighting_fast_charging_static': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingStatic'), + 'lighting_fast_charging_none': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingNone'), + 'lighting_fast_charging_wave': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingWave'), + 'lighting_fast_charging_breath_single': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingBreathSingle'), + 'lighting_fast_charging_breath_dual': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingBreathDual'), + 'lighting_fast_charging_breath_random': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingBreathRandom'), + 'lighting_fast_charging_breath_mono': self._has_feature('razer.device.lighting.fast_charging', 'setFastChargingBreathMono'), + + 'lighting_fully_charged': self._has_feature('razer.device.lighting.fully_charged'), + 'lighting_fully_charged_active': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedActive'), + 'lighting_fully_charged_brightness': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedBrightness'), + 'lighting_fully_charged_spectrum': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedSpectrum'), + 'lighting_fully_charged_static': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedStatic'), + 'lighting_fully_charged_none': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedNone'), + 'lighting_fully_charged_wave': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedWave'), + 'lighting_fully_charged_breath_single': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedBreathSingle'), + 'lighting_fully_charged_breath_dual': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedBreathDual'), + 'lighting_fully_charged_breath_random': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedBreathRandom'), + 'lighting_fully_charged_breath_mono': self._has_feature('razer.device.lighting.fully_charged', 'setFullyChargedBreathMono'), + } + + # Nasty hack to convert dbus.Int32 into native + if self.has('lighting_led_matrix'): + self._matrix_dimensions = tuple([int(dim) for dim in self._dbus_interfaces['device'].getMatrixDimensions()]) + else: + self._matrix_dimensions = None + + if self.has('keyboard_layout'): + self._kbd_layout = str(self._dbus_interfaces['device'].getKeyboardLayout()) + else: + self._kbd_layout = None + + # Setup FX + if self._FX is None: + self.fx = None + else: + self.fx = self._FX(serial, capabilities=self._capabilities, daemon_dbus=daemon_dbus, matrix_dims=self._matrix_dimensions) + + # Setup Macro + if self.has('macro_logic'): + if self._MACRO_CLASS is not None: + self.macro = self._MACRO_CLASS(serial, self.name, daemon_dbus=daemon_dbus, capabilities=self._capabilities) + else: + self._capabilities['macro_logic'] = False + self.macro = None + else: + self.macro = None + + if self.has('dpi'): + self._dbus_interfaces['dpi'] = _dbus.Interface(self._dbus, "razer.device.dpi") + if self.has('battery'): + self._dbus_interfaces['power'] = _dbus.Interface(self._dbus, "razer.device.power") + if self.has('game_mode_led'): + self._dbus_interfaces['game_mode_led'] = _dbus.Interface(self._dbus, "razer.device.led.gamemode") + if self.has('keyswitch_optimization'): + self._dbus_interfaces['keyswitch_optimization'] = _dbus.Interface(self._dbus, "razer.device.misc.keyswitchoptimization") + if self.has('macro_mode_led'): + self._dbus_interfaces['macro_mode_led'] = _dbus.Interface(self._dbus, "razer.device.led.macromode") + if self.has('lighting_profile_led_red') or self.has('lighting_profile_led_green') or self.has('lighting_profile_led_blue'): + self._dbus_interfaces['profile_led'] = _dbus.Interface(self._dbus, "razer.device.lighting.profile_led") + if self.has('scroll_mode') or self.has('scroll_acceleration') or self.has('scroll_smart_reel'): + self._dbus_interfaces['scroll'] = _dbus.Interface(self._dbus, "razer.device.scroll") + + def _get_available_features(self): + introspect_interface = _dbus.Interface(self._dbus, 'org.freedesktop.DBus.Introspectable') + xml_spec = introspect_interface.Introspect() + root = _ET.fromstring(xml_spec) + + interfaces = {} + + for child in root: + + if child.tag != 'interface' or child.attrib.get('name') == 'org.freedesktop.DBus.Introspectable': + continue + + current_interface = child.attrib['name'] + current_interface_methods = [] + + for method in child: + if method.tag != 'method': + continue + + current_interface_methods.append(method.attrib.get('name')) + + interfaces[current_interface] = current_interface_methods + + return interfaces + + def _has_feature(self, object_path: str, method_name=None) -> bool: + """ + Checks to see if the device has said DBus method + + :param object_path: Object path + :type object_path: str + + :param method_name: Method name, or list of methods + :type method_name: str or list or tuple + + :return: True if method/s exist + :rtype: bool + """ + if method_name is None: + return object_path in self._available_features + elif isinstance(method_name, str): + return object_path in self._available_features and method_name in self._available_features[object_path] + elif isinstance(method_name, (list, tuple)): + result = True + for method in method_name: + result &= object_path in self._available_features and method in self._available_features[object_path] + return result + else: + return False + + def has(self, capability: str) -> bool: + """ + Convenience function to check capability + + :param capability: Device capability + :type capability: str + + :return: True or False + :rtype: bool + """ + # Could do capability in self._capabilitys but they might be explicitly disabled + return self._capabilities.get(capability, False) + + @property + def name(self) -> str: + """ + Device name + + :return: Device Name + :rtype: str + """ + return self._name + + @property + def type(self) -> str: + """ + Get device type + + :return: Device Type + :rtype: str + """ + return self._type + + @property + def firmware_version(self) -> str: + """ + Device's firmware version + + :return: FW Version + :rtype: str + """ + return self._fw + + @property + def driver_version(self) -> str: + """ + Device's driver version + + :return: Driver Version + :rtype: str + """ + return self._drv_version + + @property + def serial(self) -> str: + """ + Device's serial + + :return: Device Serial + :rtype: str + """ + return self._serial + + @property + def keyboard_layout(self) -> str: + """ + Device's keyboard layout + + :return: Keyboard layout + :rtype: str + """ + return self._kbd_layout + + @property + def brightness(self) -> float: + """ + Get device brightness + + :return: Device brightness + :rtype: float + """ + return self._dbus_interfaces['brightness'].getBrightness() + + @brightness.setter + def brightness(self, value: float): + """ + Set device brightness + + :param value: Device brightness + :type value: float + + :raises ValueError: When brightness is not a float or not in range 0.0->100.0 + """ + if isinstance(value, int): + value = float(value) + + if not isinstance(value, float): + raise ValueError("Brightness must be a float") + + if value < 0.0 or value > 100.0: + raise ValueError("Brightness must be between 0 and 100") + + self._dbus_interfaces['brightness'].setBrightness(value) + + @property + def capabilities(self) -> dict: + """ + Device capabilities + + :return: Device capabilities + :rtype: dict + """ + return self._capabilities + + @property + def dedicated_macro(self) -> bool: + """ + Device has dedicated macro keys + + :return: If the device has macro keys + :rtype: bool + """ + if self._has_dedicated_macro is None: + self._has_dedicated_macro = self._dbus_interfaces['device'].hasDedicatedMacroKeys() + + return self._has_dedicated_macro + + @property + def device_image(self) -> str: + if self._device_image is None: + self._device_image = str(self._dbus_interfaces['device'].getDeviceImage()) + + return self._device_image + + @property + def razer_urls(self) -> dict: + # Deprecated API, but kept for backwards compatibility + return { + "DEPRECATED": True, + "top_img": self.device_image, + "side_img": self.device_image, + "perspective_img": self.device_image + } + + @property + def battery_level(self) -> int: + """ + Get battery level from device + + :return: Battery level (0-100) + """ + if self.has('battery'): + return int(self._dbus_interfaces['power'].getBattery()) + + @property + def is_charging(self) -> bool: + """ + Get whether the device is charging or not + + :return: Boolean + """ + if self.has('battery'): + return bool(self._dbus_interfaces['power'].isCharging()) + + def set_idle_time(self, idle_time) -> None: + """ + Sets the idle time on the device + + :param idle_time: the time in seconds + """ + if self.has('battery'): + self._dbus_interfaces['power'].setIdleTime(idle_time) + + def get_idle_time(self) -> int: + """ + Gets the idle time of the device + + :return: Number of seconds before this device goes into powersave + (60-900) + """ + if self.has('battery'): + return int(self._dbus_interfaces['power'].getIdleTime()) + + def set_low_battery_threshold(self, threshold) -> None: + """ + Set the low battery threshold as a percentage + + :param threshold: Battery threshold as a percentage + :type threshold: int + """ + if self.has('battery'): + self._dbus_interfaces['power'].setLowBatteryThreshold(threshold) + + def get_low_battery_threshold(self) -> int: + """ + Get the low battery threshold as a percentage + + :return: Battery threshold as a percentage + """ + if self.has('battery'): + return int(self._dbus_interfaces['power'].getLowBatteryThreshold()) + + @property + def poll_rate(self) -> int: + """ + Get poll rate from device + + :return: Poll rate + :rtype: int + + :raises NotImplementedError: If function is not supported + """ + if self.has('poll_rate'): + return int(self._dbus_interfaces['device'].getPollRate()) + else: + raise NotImplementedError() + + @poll_rate.setter + def poll_rate(self, poll_rate: int): + """ + Set poll rate of device + + :param poll_rate: Polling rate + :type poll_rate: int + + :raises NotImplementedError: If function is not supported + """ + if self.has('poll_rate'): + if not isinstance(poll_rate, int): + raise ValueError("Poll rate is not an integer: {0}".format(poll_rate)) + + self._dbus_interfaces['device'].setPollRate(poll_rate) + + else: + raise NotImplementedError() + + @property + def supported_poll_rates(self) -> list: + """ + Get poll rates supported by the device + + :return: Supported poll rates + :rtype: list + + :raises NotImplementedError: If function is not supported + """ + if self.has('supported_poll_rates'): + dbuslist = self._dbus_interfaces['device'].getSupportedPollRates() + # Repack list from dbus ints to normal ints + return [int(d) for d in dbuslist] + else: + raise NotImplementedError() + + def __str__(self): + return self._name + + def __repr__(self): + return '<{0} {1}>'.format(self.__class__.__name__, self._serial) + + +class BaseDeviceFactory(object): + @staticmethod + def get_device(serial: str, daemon_dbus=None) -> RazerDevice: + raise NotImplementedError() diff --git a/openrazer/pylib/openrazer/client/devices/keyboard.py b/openrazer/pylib/openrazer/client/devices/keyboard.py new file mode 100644 index 00000000..30ce3612 --- /dev/null +++ b/openrazer/pylib/openrazer/client/devices/keyboard.py @@ -0,0 +1,207 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +""" +Contains functionality specific to keyboard-like devices +""" +import dbus as _dbus + +from openrazer.client.constants import MACRO_LED_STATIC, MACRO_LED_BLINK +from openrazer.client.devices import RazerDevice as __RazerDevice, BaseDeviceFactory as __BaseDeviceFactory + + +class RazerKeyboard(__RazerDevice): + @property + def game_mode_led(self) -> bool: + """ + Get game mode LED state + + :return: LED state + :rtype: bool + """ + if self.has('game_mode_led'): + return self._dbus_interfaces['game_mode_led'].getGameMode() + else: + return False + + @game_mode_led.setter + def game_mode_led(self, value: bool): + """ + Set game mode LED state + + :param value: LED State + :type value: bool + """ + if self.has('game_mode_led'): + if value: + self._dbus_interfaces['game_mode_led'].setGameMode(True) + else: + self._dbus_interfaces['game_mode_led'].setGameMode(False) + + @property + def macro_mode_led(self) -> bool: + """ + Get macro mode LED state + + :return: LED state + :rtype: bool + """ + if self.has('macro_mode_led'): + return self._dbus_interfaces['macro_mode_led'].getMacroMode() + else: + return False + + @macro_mode_led.setter + def macro_mode_led(self, value: bool): + """ + Set macro mode LED state + + :param value: LED State + :type value: bool + """ + if self.has('macro_mode_led'): + if value: + self._dbus_interfaces['macro_mode_led'].setMacroMode(True) + else: + self._dbus_interfaces['macro_mode_led'].setMacroMode(False) + + @property + def macro_mode_led_effect(self) -> int: + """ + Get macro mode LED effect + + Can get either blinking or static + :return: Effect ID + :rtype: int + """ + if self.has('macro_mode_led_effect'): + return self._dbus_interfaces['macro_mode_led'].getMacroEffect() + else: + return False + + @macro_mode_led_effect.setter + def macro_mode_led_effect(self, value: int): + """ + Set macro mode LED effect + + Can set to either MACRO_LED_STATIC or MACRO_LED_BLINK + :param value: Effect ID + :type value: int + """ + if self.has('macro_mode_led_effect') and value in (MACRO_LED_STATIC, MACRO_LED_BLINK): + self._dbus_interfaces['macro_mode_led'].setMacroEffect(value) + + @property + def keyswitch_optimization(self) -> bool: + """ + Get keyswitch optimization state + + :return: Keyswitch optimization state + :rtype: bool + """ + if self.has('keyswitch_optimization'): + return self._dbus_interfaces['keyswitch_optimization'].getKeyswitchOptimization() + else: + return False + + @keyswitch_optimization.setter + def keyswitch_optimization(self, value: bool): + """ + Set keyswitch optimization state + + :param value: Keyswitch optimization state + :type value: bool + """ + if self.has('keyswitch_optimization'): + if value: + self._dbus_interfaces['keyswitch_optimization'].setKeyswitchOptimization(True) + else: + self._dbus_interfaces['keyswitch_optimization'].setKeyswitchOptimization(False) + + @property + def profile_led_red(self) -> bool: + """ + Get red profile LED state + + :return: Red profile LED state + :rtype: bool + """ + if self.has('lighting_profile_led_red'): + return bool(self._dbus_interfaces['profile_led'].getRedLED()) + else: + return False + + @profile_led_red.setter + def profile_led_red(self, enable: bool): + """ + Set red profile LED state + + :param enable: Status of red profile LED + :type enable: bool + """ + if self.has('lighting_profile_led_red'): + self._dbus_interfaces['profile_led'].setRedLED(enable) + + @property + def profile_led_green(self) -> bool: + """ + Get green profile LED state + + :return: Green profile LED state + :rtype: bool + """ + if self.has('lighting_profile_led_green'): + return bool(self._dbus_interfaces['profile_led'].getGreenLED()) + else: + return False + + @profile_led_green.setter + def profile_led_green(self, enable: bool): + """ + Set green profile LED state + + :param enable: Status of green profile LED + :type enable: bool + """ + if self.has('lighting_profile_led_green'): + self._dbus_interfaces['profile_led'].setGreenLED(enable) + + @property + def profile_led_blue(self) -> bool: + """ + Get blue profile LED state + + :return: Blue profile LED state + :rtype: bool + """ + if self.has('lighting_profile_led_blue'): + return bool(self._dbus_interfaces['profile_led'].getBlueLED()) + else: + return False + + @profile_led_blue.setter + def profile_led_blue(self, enable: bool): + """ + Set blue profile LED state + + :param enable: Status of blue profile LED + :type enable: bool + """ + if self.has('lighting_profile_led_blue'): + self._dbus_interfaces['profile_led'].setBlueLED(enable) + + +DEVICE_PID_MAP = { + +} + + +class RazerKeyboardFactory(__BaseDeviceFactory): + @staticmethod + def get_device(serial, vid_pid=None, daemon_dbus=None): + if vid_pid is None: + pid = 0xFFFF + else: + pid = vid_pid[1] + + device_class = DEVICE_PID_MAP.get(pid, RazerKeyboard) + return device_class(serial, vid_pid=vid_pid, daemon_dbus=daemon_dbus) diff --git a/openrazer/pylib/openrazer/client/devices/mice.py b/openrazer/pylib/openrazer/client/devices/mice.py new file mode 100644 index 00000000..9750d03d --- /dev/null +++ b/openrazer/pylib/openrazer/client/devices/mice.py @@ -0,0 +1,270 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import dbus as _dbus + +from openrazer.client.devices import RazerDevice as __RazerDevice +from openrazer.client.macro import RazerMacro as _RazerMacro + + +class RazerMouse(__RazerDevice): + _MACRO_CLASS = _RazerMacro + + @property + def max_dpi(self) -> int: + """ + Gets max DPI + + :return: Max DPI, if device does not have DPI it'll return None + :rtype: int or None + """ + if self.has('dpi'): + return int(self._dbus_interfaces['dpi'].maxDPI()) + else: + return None + + @property + def available_dpi(self) -> list: + """ + Gets the available DPI + + :return: Available DPI, if device has only a couple of fixed possible DPI values + :rtype: list or None + """ + if self.has('available_dpi'): + dbuslist = self._dbus_interfaces['dpi'].availableDPI() + # Repack list from dbus ints to normal ints + return [int(d) for d in dbuslist] + else: + return None + + @property + def dpi(self) -> tuple: + """ + Get mouse DPI + + Will return a tuple + :return: DPI (500, 500) + :rtype: tuple + + :raises NotImplementedError: If function is not supported + """ + if self.has('available_dpi'): + dpi_x = self._dbus_interfaces['dpi'].getDPI()[0] + return int(dpi_x), 0 + elif self.has('dpi'): + dpi_x, dpi_y = self._dbus_interfaces['dpi'].getDPI() + # Converting to integers to remove the dbus types + return int(dpi_x), int(dpi_y) + else: + raise NotImplementedError() + + @dpi.setter + def dpi(self, value: tuple): + """ + Set mouse dpi + + Daemon does type validation but can't be too careful + :param value: DPI X, Y tuple + :type value: tuple + + :raises ValueError: If the tuple isn't long enough or contains invalid crap + :raises NotImplementedError: If function is not supported + """ + if self.has('dpi'): + if len(value) != 2: + raise ValueError("DPI tuple is not of length 2. Length: {0}".format(len(value))) + max_dpi = self.max_dpi + dpi_x, dpi_y = value + dpi_x_only = self.has('available_dpi') + + if not isinstance(dpi_x, int) or not isinstance(dpi_y, int): + raise ValueError("DPI X or Y is not an integer, X:{0} Y:{1}".format(type(dpi_x), type(dpi_y))) + + if dpi_x < 0 or dpi_x > max_dpi: + raise ValueError("DPI X either too small or too large, X:{0}".format(dpi_x)) + + if dpi_x_only and not dpi_y == 0: + raise ValueError("DPI Y is not supported for this device") + elif dpi_y < 0 or dpi_y > max_dpi: + raise ValueError("DPI Y either too small or too large, Y:{0}".format(dpi_y)) + + self._dbus_interfaces['dpi'].setDPI(dpi_x, dpi_y) + else: + raise NotImplementedError() + + @property + def dpi_stages(self) -> (int, list): + """ + Get mouse DPI stages + + Will return a tuple containing the active DPI stage number and the list + of DPI stages as tuples. + The active DPI stage number must be: >= 1 and <= nr of DPI stages. + :return: active DPI stage number and DPI stages + (1, [(500, 500), (1000, 1000), (2000, 2000) ...] + :rtype: (int, list) + + :raises NotImplementedError: if function is not supported + """ + if self.has('dpi_stages'): + response = self._dbus_interfaces['dpi'].getDPIStages() + dpi_stages = [] + + active_stage = int(response[0]) + + for dpi_x, dpi_y in response[1]: + dpi_stages.append((int(dpi_x), int(dpi_y))) + + return (active_stage, dpi_stages) + else: + raise NotImplementedError() + + @dpi_stages.setter + def dpi_stages(self, value: (int, list)): + """ + Set mouse DPI stages + + Daemon does type validation but can't be too careful + :param value: active DPI stage number and list of DPI X, Y tuples + :type value: (int, list) + + :raises ValueError: when the input is invalid + :raises NotImplementedError: If function is not supported + """ + if self.has('dpi_stages'): + max_dpi = self.max_dpi + dpi_stages = [] + + active_stage = value[0] + if not isinstance(active_stage, int): + raise ValueError( + "Active DPI stage is not an integer: {0}".format( + type(active_stage))) + + if active_stage < 1: + raise ValueError( + "Active DPI stage has invalid value: {0} < 1".format( + active_stage)) + + for stage in value[1]: + if len(stage) != 2: + raise ValueError( + "DPI tuple is not of length 2. Length: {0}".format( + len(stage))) + + dpi_x, dpi_y = stage + + if not isinstance(dpi_x, int) or not isinstance(dpi_y, int): + raise ValueError( + "DPI X or Y is not an integer, X:{0} Y:{1}".format( + type(dpi_x), type(dpi_y))) + + if dpi_x < 0 or dpi_x > max_dpi: + raise ValueError( + "DPI X either too small or too large, X:{0}".format( + dpi_x)) + if dpi_y < 0 or dpi_y > max_dpi: + raise ValueError( + "DPI Y either too small or too large, Y:{0}".format( + dpi_y)) + + dpi_stages.append((dpi_x, dpi_y)) + + if active_stage > len(dpi_stages): + raise ValueError( + "Active DPI stage has invalid value: {0} > {1}".format( + active_stage, len(dpi_stages))) + + self._dbus_interfaces['dpi'].setDPIStages(active_stage, dpi_stages) + else: + raise NotImplementedError() + + @property + def scroll_mode(self) -> int: + """ + Get the scroll wheel mode of the device + + :return: The device's current scroll mode (0 = tactile, 1 = free spin) + :rtype: int + + :raises NotImplementedError: If function is not supported + """ + if self.has('scroll_mode'): + return int(self._dbus_interfaces['scroll'].getScrollMode()) + else: + raise NotImplementedError() + + @scroll_mode.setter + def scroll_mode(self, mode: int): + """ + Set the scroll mode of the device + + :param mode: The mode to set (0 = tactile, 1 = free spin) + :type mode: int + + :raises NotImplementedError: If function is not supported + """ + if self.has('scroll_mode'): + self._dbus_interfaces['scroll'].setScrollMode(mode) + else: + raise NotImplementedError() + + @property + def scroll_acceleration(self) -> bool: + """ + Get the device's scroll acceleration state + + :return: true if acceleration enabled, false otherwise + :rtype: bool + + :raises NotImplementedError: If function is not supported + """ + if self.has('scroll_acceleration'): + return bool(int(self._dbus_interfaces['scroll'].getScrollAcceleration())) + else: + raise NotImplementedError() + + @scroll_acceleration.setter + def scroll_acceleration(self, enabled: bool): + """ + Set the device's scroll acceleration state + + :param enabled: true to enable acceleration, false to disable it + :type enabled: bool + + :raises NotImplementedError: If function is not supported + """ + if self.has('scroll_acceleration'): + self._dbus_interfaces['scroll'].setScrollAcceleration(enabled) + else: + raise NotImplementedError() + + @property + def scroll_smart_reel(self) -> bool: + """ + Get the device's "smart reel" state + + :return: true if smart reel enabled, false otherwise + :rtype: bool + + :raises NotImplementedError: If function is not supported + """ + if self.has('scroll_smart_reel'): + return bool(int(self._dbus_interfaces['scroll'].getScrollSmartReel())) + else: + raise NotImplementedError() + + @scroll_smart_reel.setter + def scroll_smart_reel(self, enabled: bool): + """ + Set the device's "smart reel" state + + :param enabled: true to enable smart reel, false to disable it + :type enabled: bool + + :raises NotImplementedError: If function is not supported + """ + if self.has('scroll_smart_reel'): + self._dbus_interfaces['scroll'].setScrollSmartReel(enabled) + else: + raise NotImplementedError() diff --git a/openrazer/pylib/openrazer/client/devices/mousemat.py b/openrazer/pylib/openrazer/client/devices/mousemat.py new file mode 100644 index 00000000..b0728ed0 --- /dev/null +++ b/openrazer/pylib/openrazer/client/devices/mousemat.py @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +from openrazer.client.devices import RazerDevice as __RazerDevice + + +class RazerMousemat(__RazerDevice): + def trigger_reactive(self) -> bool: + """ + Trigger a reactive flash + """ + return self._dbus_interfaces['device'].triggerReactive() diff --git a/openrazer/pylib/openrazer/client/fx.py b/openrazer/pylib/openrazer/client/fx.py new file mode 100644 index 00000000..91c03bc8 --- /dev/null +++ b/openrazer/pylib/openrazer/client/fx.py @@ -0,0 +1,1241 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import numpy as _np +import dbus as _dbus +# from openrazer.client.constants import WAVE_LEFT, WAVE_RIGHT, REACTIVE_500MS, REACTIVE_1000MS, REACTIVE_1500MS, REACTIVE_2000MS +from openrazer.client import constants as c + +# TODO logging.debug if value out of range v1.1 + + +def clamp_ubyte(value): + """ + Clamp a value to 0->255 + + Aka -3453 + :param value: Integer + :type value: int + + :return: Integer 0->255 + :rtype: int + """ + if value > 255: + value = 255 + elif value < 0: + value = 0 + return value + + +# Default Chroma lighting +class BaseRazerFX(object): + def __init__(self, serial: str, capabilities: dict, daemon_dbus=None): + self._capabilities = capabilities + + if daemon_dbus is None: + session_bus = _dbus.SessionBus() + daemon_dbus = session_bus.get_object("org.razer", "/org/razer/device/{0}".format(serial)) + self._dbus = daemon_dbus + + def has(self, capability: str) -> bool: + """ + Convenience function to check capability + + Uses the main device capability list and automatically prefixes 'lighting_' + :param capability: Device capability + :type capability: str + + :return: True or False + :rtype: bool + """ + return self._capabilities.get('lighting_' + capability, False) + + +class RazerFX(BaseRazerFX): + def __init__(self, serial: str, capabilities: dict, daemon_dbus=None, matrix_dims=(-1, -1)): + super().__init__(serial, capabilities, daemon_dbus) + + self._lighting_dbus = _dbus.Interface(self._dbus, "razer.device.lighting.chroma") + + # all() part basically checks that all dimensions are present (-1 is bad) + if self.has('led_matrix') and all([dim >= 1 for dim in matrix_dims]): + self.advanced = RazerAdvancedFX(serial, capabilities, daemon_dbus=self._dbus, matrix_dims=matrix_dims) + else: + self.advanced = None + + # Only keyboards will have ripple set + if self.has('led_matrix') and self.has('ripple'): + self._custom_lighting_dbus = _dbus.Interface(self._dbus, "razer.device.lighting.custom") + else: + self._custom_lighting_dbus = None + + self.misc = MiscLighting(serial, capabilities, self._dbus) + + @property + def effect(self) -> str: + """ + Get current effect + + :return: Effect name ("static", "spectrum", etc.) + :rtype: str + """ + return self._lighting_dbus.getEffect() + + @property + def colors(self) -> bytearray: + """ + Get current effect colors + + :return: Effect colors (an array of 9 bytes, for 3 colors in RGB format) + :rtype: bytearray + """ + return bytes(self._lighting_dbus.getEffectColors()) + + @property + def speed(self) -> int: + """ + Get current effect speed + + :return: Effect speed (a value between 0 and 3) + :rtype: int + """ + return self._lighting_dbus.getEffectSpeed() + + @property + def wave_dir(self) -> int: + """ + Get current wave direction + + :return: Wave direction (WAVE_LEFT or WAVE_RIGHT) + :rtype: int + """ + return self._lighting_dbus.getWaveDir() + + def none(self) -> bool: + """ + No effect + + :return: True if success, False otherwise + :rtype: bool + """ + if self.has('none'): + self._lighting_dbus.setNone() + + return True + return False + + def spectrum(self) -> bool: + """ + Spectrum effect + + :return: True if success, False otherwise + :rtype: bool + """ + if self.has('spectrum'): + self._lighting_dbus.setSpectrum() + + return True + return False + + def wave(self, direction: int) -> bool: + """ + Wave effect + + :param direction: Wave direction either WAVE_RIGHT (0x01) or WAVE_LEFT (0x02) + :type direction: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If direction is invalid + """ + if direction not in (c.WAVE_LEFT, c.WAVE_RIGHT): + raise ValueError("Direction must be WAVE_RIGHT (0x01) or WAVE_LEFT (0x02)") + + if self.has('wave'): + self._lighting_dbus.setWave(direction) + + return True + return False + + def wheel(self, direction: int) -> bool: + """ + Wheel effect + + :param direction: Wheel direction either WHEEL_RIGHT or WHEEL_LEFT + :type direction: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If direction is invalid + """ + if direction not in (c.WHEEL_LEFT, c.WHEEL_RIGHT): + raise ValueError("Direction must be WHEEL_RIGHT (0x01) or WHEEL_LEFT (0x02)") + + if self.has('wheel'): + self._lighting_dbus.setWheel(direction) + + return True + return False + + def static(self, red: int, green: int, blue: int) -> bool: + """ + Static effect + + :param red: Red component. Must be 0->255 + :type red: int + + :param green: Green component. Must be 0->255 + :type green: int + + :param blue: Blue component. Must be 0->255 + :type blue: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self.has('static'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._lighting_dbus.setStatic(red, green, blue) + + return True + return False + + def reactive(self, red: int, green: int, blue: int, time: int) -> bool: + """ + Reactive effect + + :param time: Reactive speed. One of REACTIVE_500MS, REACTIVE_1000MS, REACTIVE_1500MS or REACTIVE_2000MS + :param time: int + + :param red: Red component. Must be 0->255 + :type red: int + + :param green: Green component. Must be 0->255 + :type green: int + + :param blue: Blue component. Must be 0->255 + :type blue: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if time not in (c.REACTIVE_500MS, c.REACTIVE_1000MS, c.REACTIVE_1500MS, c.REACTIVE_2000MS): + raise ValueError("Time not one of REACTIVE_500MS, REACTIVE_1000MS, REACTIVE_1500MS or REACTIVE_2000MS") + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self.has('reactive'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._lighting_dbus.setReactive(red, green, blue, time) + + return True + return False + + def breath_single(self, red: int, green: int, blue: int) -> bool: + """ + Breath effect - single colour + + :param red: Red component. Must be 0->255 + :type red: int + + :param green: Green component. Must be 0->255 + :type green: int + + :param blue: Blue component. Must be 0->255 + :type blue: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self.has('breath_single'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._lighting_dbus.setBreathSingle(red, green, blue) + + return True + return False + + # TODO Change to tuple of rgb + def breath_dual(self, red: int, green: int, blue: int, red2: int, green2: int, blue2: int) -> bool: + """ + Breath effect - single colour + + :param red: First red component. Must be 0->255 + :type red: int + + :param green: First green component. Must be 0->255 + :type green: int + + :param blue: First blue component. Must be 0->255 + :type blue: int + + :param red2: Second red component. Must be 0->255 + :type red2: int + + :param green2: Second green component. Must be 0->255 + :type green2: int + + :param blue2: Second blue component. Must be 0->255 + :type blue2: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if not isinstance(red, int): + raise ValueError("Primary red is not an integer") + if not isinstance(green, int): + raise ValueError("Primary green is not an integer") + if not isinstance(blue, int): + raise ValueError("Primary blue is not an integer") + if not isinstance(red2, int): + raise ValueError("Secondary red is not an integer") + if not isinstance(green2, int): + raise ValueError("Secondary green is not an integer") + if not isinstance(blue2, int): + raise ValueError("Secondary blue is not an integer") + + if self.has('breath_dual'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + red2 = clamp_ubyte(red2) + green2 = clamp_ubyte(green2) + blue2 = clamp_ubyte(blue2) + + self._lighting_dbus.setBreathDual(red, green, blue, red2, green2, blue2) + + return True + return False + + def breath_triple(self, red: int, green: int, blue: int, red2: int, green2: int, blue2: int, red3: int, green3: int, blue3: int) -> bool: + """ + Breath effect - single colour + + :param red: First red component. Must be 0->255 + :type red: int + + :param green: First green component. Must be 0->255 + :type green: int + + :param blue: First blue component. Must be 0->255 + :type blue: int + + :param red2: Second red component. Must be 0->255 + :type red2: int + + :param green2: Second green component. Must be 0->255 + :type green2: int + + :param blue2: Second blue component. Must be 0->255 + :type blue2: int + + :param red3: Second red component. Must be 0->255 + :type red3: int + + :param green3: Second green component. Must be 0->255 + :type green3: int + + :param blue3: Second blue component. Must be 0->255 + :type blue3: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if not isinstance(red, int): + raise ValueError("Primary red is not an integer") + if not isinstance(green, int): + raise ValueError("Primary green is not an integer") + if not isinstance(blue, int): + raise ValueError("Primary blue is not an integer") + if not isinstance(red2, int): + raise ValueError("Secondary red is not an integer") + if not isinstance(green2, int): + raise ValueError("Secondary green is not an integer") + if not isinstance(blue2, int): + raise ValueError("Secondary blue is not an integer") + if not isinstance(red3, int): + raise ValueError("Tertiary red is not an integer") + if not isinstance(green3, int): + raise ValueError("Tertiary green is not an integer") + if not isinstance(blue3, int): + raise ValueError("Tertiary blue is not an integer") + + if self.has('breath_triple'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + red2 = clamp_ubyte(red2) + green2 = clamp_ubyte(green2) + blue2 = clamp_ubyte(blue2) + red3 = clamp_ubyte(red3) + green3 = clamp_ubyte(green3) + blue3 = clamp_ubyte(blue3) + + self._lighting_dbus.setBreathTriple(red, green, blue, red2, green2, blue2, red3, green3, blue3) + + return True + return False + + def breath_random(self) -> bool: + """ + Breath effect - random colours + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + + if self.has('breath_random'): + self._lighting_dbus.setBreathRandom() + + return True + return False + + def ripple(self, red: int, green: int, blue: int, refreshrate: float = c.RIPPLE_REFRESH_RATE) -> bool: + """ + Set the Ripple Effect. + + The refresh rate should be set to about 0.05 for a decent effect + :param red: Red RGB component + :rtype red: int + + :param green: Green RGB component + :type green: int + + :param blue: Blue RGB component + :type blue: int + + :param refreshrate: Effect refresh rate + :type refreshrate: float + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If arguments are invalid + """ + if not isinstance(refreshrate, float): + raise ValueError("Refresh rate is not a float") + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self.has('ripple'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._custom_lighting_dbus.setRipple(red, green, blue, refreshrate) + + return True + return False + + def ripple_random(self, refreshrate: float = c.RIPPLE_REFRESH_RATE): + """ + Set the Ripple Effect with random colours + + The refresh rate should be set to about 0.05 for a decent effect + :param refreshrate: Effect refresh rate + :type refreshrate: float + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If arguments are invalid + """ + if not isinstance(refreshrate, float): + raise ValueError("Refresh rate is not a float") + + if self.has('ripple_random'): + self._custom_lighting_dbus.setRippleRandomColour(refreshrate) + + return True + return False + + def starlight_single(self, red: int, green: int, blue: int, time: int) -> bool: + """ + Starlight effect + + :param red: Red component. Must be 0->255 + :type red: int + + :param green: Green component. Must be 0->255 + :type green: int + + :param blue: Blue component. Must be 0->255 + :type blue: int + + :param time: Starlight speed + :type time: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if time not in (c.STARLIGHT_FAST, c.STARLIGHT_NORMAL, c.STARLIGHT_SLOW): + raise ValueError("Time not one of STARLIGHT_FAST, STARLIGHT_NORMAL or STARLIGHT_SLOW") + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self.has('starlight_single'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._lighting_dbus.setStarlightSingle(red, green, blue, time) + + return True + return False + + def starlight_dual(self, red: int, green: int, blue: int, red2: int, green2: int, blue2: int, time: int) -> bool: + """ + Starlight effect + + :param red: Red component. Must be 0->255 + :type red: int + + :param green: Green component. Must be 0->255 + :type green: int + + :param blue: Blue component. Must be 0->255 + :type blue: int + + :param red2: Red component. Must be 0->255 + :type red2: int + + :param green2: Green component. Must be 0->255 + :type green2: int + + :param blue2: Blue component. Must be 0->255 + :type blue2: int + + :param time: Starlight speed + :type time: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if time not in (c.STARLIGHT_FAST, c.STARLIGHT_NORMAL, c.STARLIGHT_SLOW): + raise ValueError("Time not one of STARLIGHT_FAST, STARLIGHT_NORMAL or STARLIGHT_SLOW") + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + if not isinstance(red2, int): + raise ValueError("Red 2 is not an integer") + if not isinstance(green2, int): + raise ValueError("Green 2 is not an integer") + if not isinstance(blue2, int): + raise ValueError("Blue 2 is not an integer") + + if self.has('starlight_dual'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + red2 = clamp_ubyte(red2) + green2 = clamp_ubyte(green2) + blue2 = clamp_ubyte(blue2) + + self._lighting_dbus.setStarlightDual(red, green, blue, red2, green2, blue2, time) + + return True + return False + + def starlight_random(self, time: int) -> bool: + """ + Starlight effect + + :param time: Starlight speed + :type time: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if time not in (c.STARLIGHT_FAST, c.STARLIGHT_NORMAL, c.STARLIGHT_SLOW): + raise ValueError("Time not one of STARLIGHT_FAST, STARLIGHT_NORMAL or STARLIGHT_SLOW") + + if self.has('starlight_random'): + self._lighting_dbus.setStarlightRandom(time) + + return True + return False + + +class RazerAdvancedFX(BaseRazerFX): + def __init__(self, serial: str, capabilities: dict, daemon_dbus=None, matrix_dims=(-1, -1)): + super().__init__(serial, capabilities, daemon_dbus) + + # Only init'd when there's a matrix + self._capabilities = capabilities + + if not all([dim >= 1 for dim in matrix_dims]): + raise ValueError("Matrix dimensions cannot contain -1") + + if daemon_dbus is None: + session_bus = _dbus.SessionBus() + daemon_dbus = session_bus.get_object("org.razer", "/org/razer/device/{0}".format(serial)) + + self._matrix_dims = matrix_dims + self._lighting_dbus = _dbus.Interface(daemon_dbus, "razer.device.lighting.chroma") + + self.matrix = Frame(matrix_dims) + + @property + def cols(self): + """ + Number of columns in matrix + + :return: Columns + :rtype: int + """ + return self._matrix_dims[1] + + @property + def rows(self): + """ + Number of rows in matrix + + :return: Rows + :rtype: int + """ + return self._matrix_dims[0] + + def _draw(self, ba): + self._lighting_dbus.setKeyRow(ba) + + self._lighting_dbus.setCustom() + + def draw(self): + """ + Draw what's in the current frame buffer + """ + self._draw(bytes(self.matrix)) + + def draw_fb_or(self): + self._draw(bytes(self.matrix.draw_with_fb_or())) + + def set_key(self, column_id, rgb, row_id=0): # Not needed on mice + if self.has('led_single'): + if isinstance(rgb, (tuple, list)) and len(rgb) == 3 and all([isinstance(component, int) for component in rgb]): + if row_id < self._matrix_dims[0] and column_id < self._matrix_dims[1]: + self._lighting_dbus.setKey(row_id, column_id, [clamp_ubyte(component) for component in rgb]) + else: + raise ValueError("Row or column out of bounds. Max dimensions are: {0},{1}".format(*self._matrix_dims)) + else: + raise ValueError("RGB must be an RGB tuple") + + def restore(self): + """ + Restore the device to the last effect + """ + self._lighting_dbus.restoreLastEffect() + + +class SingleLed(BaseRazerFX): + def __init__(self, serial: str, capabilities: dict, daemon_dbus=None, led_name='logo'): + super().__init__(serial, capabilities, daemon_dbus) + + self._led_name = led_name + self._lighting_dbus = _dbus.Interface(self._dbus, "razer.device.lighting.{0}".format(led_name)) + + def _shas(self, item): + return self.has('{0}_{1}'.format(self._led_name, item)) + + def _getattr(self, name): + attr = name.replace('#', self._led_name.title().replace("_", "")) + return getattr(self._lighting_dbus, attr, None) + + @property + def active(self) -> bool: + func = self._getattr('get#Active') + if func is not None: + return func() + else: + return False + + @active.setter + def active(self, value: bool): + func = self._getattr('set#Active') + if func is not None: + if value: + func(True) + else: + func(False) + + @property + def effect(self) -> str: + """ + Get current effect + + :return: Effect name ("static", "spectrum", etc.) + :rtype: str + """ + return str(self._getattr('get#Effect')()) + + @property + def colors(self) -> bytearray: + """ + Get current effect colors + + :return: Effect colors (an array of 9 bytes, for 3 colors in RGB format) + :rtype: bytearray + """ + return bytes(self._getattr('get#EffectColors')()) + + @property + def speed(self) -> int: + """ + Get current effect speed + + :return: Effect speed (a value between 0 and 3) + :rtype: int + """ + return int(self._getattr('get#EffectSpeed')()) + + @property + def wave_dir(self) -> int: + """ + Get current wave direction + + :return: Wave direction (WAVE_LEFT or WAVE_RIGHT) + :rtype: int + """ + return int(self._getattr('get#WaveDir')()) + + @property + def brightness(self): + if self._shas('brightness'): + return float(self._getattr('get#Brightness')()) + return 0.0 + + @brightness.setter + def brightness(self, brightness: float): + if self._shas('brightness'): + if not isinstance(brightness, (float, int)): + raise ValueError("Brightness is not a float") + + if brightness > 100: + brightness = 100.0 + elif brightness < 0: + brightness = 0.0 + + self._getattr('set#Brightness')(brightness) + + def blinking(self, red: int, green: int, blue: int) -> bool: + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self._shas('blinking'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._getattr('set#Blinking')(red, green, blue) + + return True + return False + + def pulsate(self, red: int, green: int, blue: int) -> bool: + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self._shas('pulsate'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._getattr('set#Pulsate')(red, green, blue) + + return True + return False + + def static(self, red: int, green: int, blue: int) -> bool: + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self._shas('static'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._getattr('set#Static')(red, green, blue) + + return True + return False + + def wave(self, direction: int) -> bool: + if direction not in (c.WAVE_LEFT, c.WAVE_RIGHT): + raise ValueError("Direction must be WAVE_RIGHT (0x01) or WAVE_LEFT (0x02)") + + if self._shas('wave'): + self._getattr('set#Wave')(direction) + + return True + return False + + def none(self) -> bool: + if self._shas('none'): + self._getattr('set#None')() + + return True + return False + + def on(self) -> bool: + if self._shas('on'): + self._getattr('set#On')() + + return True + return False + + def spectrum(self) -> bool: + if self._shas('spectrum'): + self._getattr('set#Spectrum')() + + return True + return False + + def reactive(self, red: int, green: int, blue: int, time: int) -> bool: + """ + Reactive effect + + :param time: Reactive speed. One of REACTIVE_500MS, REACTIVE_1000MS, REACTIVE_1500MS or REACTIVE_2000MS + :param time: int + + :param red: Red component. Must be 0->255 + :type red: int + + :param green: Green component. Must be 0->255 + :type green: int + + :param blue: Blue component. Must be 0->255 + :type blue: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if time not in (c.REACTIVE_500MS, c.REACTIVE_1000MS, c.REACTIVE_1500MS, c.REACTIVE_2000MS): + raise ValueError("Time not one of REACTIVE_500MS, REACTIVE_1000MS, REACTIVE_1500MS or REACTIVE_2000MS") + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self._shas('reactive'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._getattr('set#Reactive')(red, green, blue, time) + + return True + return False + + def breath_single(self, red: int, green: int, blue: int) -> bool: + """ + Breath effect - single colour + + :param red: Red component. Must be 0->255 + :type red: int + + :param green: Green component. Must be 0->255 + :type green: int + + :param blue: Blue component. Must be 0->255 + :type blue: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if not isinstance(red, int): + raise ValueError("Red is not an integer") + if not isinstance(green, int): + raise ValueError("Green is not an integer") + if not isinstance(blue, int): + raise ValueError("Blue is not an integer") + + if self._shas('breath_single'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + + self._getattr('set#BreathSingle')(red, green, blue) + + return True + return False + + # TODO Change to tuple of rgb + def breath_dual(self, red: int, green: int, blue: int, red2: int, green2: int, blue2: int) -> bool: + """ + Breath effect - single colour + + :param red: First red component. Must be 0->255 + :type red: int + + :param green: First green component. Must be 0->255 + :type green: int + + :param blue: First blue component. Must be 0->255 + :type blue: int + + :param red2: Second red component. Must be 0->255 + :type red2: int + + :param green2: Second green component. Must be 0->255 + :type green2: int + + :param blue2: Second blue component. Must be 0->255 + :type blue2: int + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + if not isinstance(red, int): + raise ValueError("Primary red is not an integer") + if not isinstance(green, int): + raise ValueError("Primary green is not an integer") + if not isinstance(blue, int): + raise ValueError("Primary blue is not an integer") + if not isinstance(red2, int): + raise ValueError("Secondary red is not an integer") + if not isinstance(green2, int): + raise ValueError("Secondary green is not an integer") + if not isinstance(blue2, int): + raise ValueError("Secondary blue is not an integer") + + if self._shas('breath_dual'): + red = clamp_ubyte(red) + green = clamp_ubyte(green) + blue = clamp_ubyte(blue) + red2 = clamp_ubyte(red2) + green2 = clamp_ubyte(green2) + blue2 = clamp_ubyte(blue2) + + self._getattr('set#BreathDual')(red, green, blue, red2, green2, blue2) + + return True + return False + + def breath_random(self) -> bool: + """ + Breath effect - random colours + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + + if self._shas('breath_random'): + self._getattr('set#BreathRandom')() + + return True + return False + + def breath_mono(self) -> bool: + """ + Breath effect - mono colour + + :return: True if success, False otherwise + :rtype: bool + + :raises ValueError: If parameters are invalid + """ + + if self._shas('breath_mono'): + self._getattr('set#BreathMono')() + + return True + return False + + +class MiscLighting(BaseRazerFX): + def __init__(self, serial: str, capabilities: dict, daemon_dbus=None): + super().__init__(serial, capabilities, daemon_dbus) + + self._lighting_dbus = _dbus.Interface(self._dbus, "razer.device.lighting.logo") + + if self.has('logo'): + self._logo = SingleLed(serial, capabilities, daemon_dbus, 'logo') + else: + self._logo = None + + if self.has('scroll'): + self._scroll = SingleLed(serial, capabilities, daemon_dbus, 'scroll') + else: + self._scroll = None + + if self.has('left'): + self._left = SingleLed(serial, capabilities, daemon_dbus, 'left') + else: + self._left = None + + if self.has('right'): + self._right = SingleLed(serial, capabilities, daemon_dbus, 'right') + else: + self._right = None + + if self.has('charging'): + self._charging = SingleLed(serial, capabilities, daemon_dbus, 'charging') + else: + self._charging = None + + if self.has('fast_charging'): + self._fast_charging = SingleLed(serial, capabilities, daemon_dbus, 'fast_charging') + else: + self._fast_charging = None + + if self.has('fully_charged'): + self._fully_charged = SingleLed(serial, capabilities, daemon_dbus, 'fully_charged') + else: + self._fully_charged = None + + if self.has('backlight'): + self._backlight = SingleLed(serial, capabilities, daemon_dbus, 'backlight') + else: + self._backlight = None + + @property + def logo(self): + return self._logo + + @property + def scroll_wheel(self): + return self._scroll + + @property + def left(self): + return self._left + + @property + def right(self): + return self._right + + @property + def charging(self): + return self._charging + + @property + def fast_charging(self): + return self._fast_charging + + @property + def fully_charged(self): + return self._fully_charged + + @property + def backlight(self): + return self._backlight + + +class Frame(object): + """ + Class to represent the RGB matrix of the keyboard. So to animate you'd use multiple frames + """ + + def __init__(self, dimensions): + self._rows, self._cols = dimensions + self._components = 3 + + self._matrix = None + self._fb1 = None + self.reset() + + # Index with row, col OR y, x + def __getitem__(self, key: tuple) -> tuple: + """ + Method to allow a slice to get an RGB tuple + + :param key: Key, must be y,x tuple + :type key: tuple + + :return: RGB tuple + :rtype: tuple + + :raises AssertionError: If key is invalid + """ + assert isinstance(key, tuple), "Key is not a tuple" + assert 0 <= key[0] < self._rows, "Row out of bounds" + assert 0 <= key[1] < self._cols, "Column out of bounds" + + return tuple(self._matrix[:, key[0], key[1]]) + + # Index with row, col OR y, x + def __setitem__(self, key: tuple, rgb: tuple): + """ + Method to allow a slice to set an RGB tuple + + :param key: Key, must be y,x tuple + :type key: tuple + + :param rgb: RGB tuple + :type rgb: tuple + + :raises AssertionError: If key is invalid + """ + assert isinstance(key, tuple), "Key is not a tuple" + assert 0 <= key[0] < self._rows, "Row out of bounds" + assert 0 <= key[1] < self._cols, "Column out of bounds" + assert isinstance(rgb, (list, tuple)) and len(rgb) == 3, "Value must be a tuple,list of 3 RGB components" + + self._matrix[:, key[0], key[1]] = rgb + + def __bytes__(self) -> bytes: + """ + When bytes() is ran on the class will return a binary capable of being sent to the driver + + :return: Driver binary payload + :rtype: bytes + """ + return b''.join([self.row_binary(row_id) for row_id in range(0, self._rows)]) + + def reset(self): + """ + Init/Clear the matrix + """ + if self._matrix is None: + self._matrix = _np.zeros((self._components, self._rows, self._cols), 'uint8') + self._fb1 = _np.copy(self._matrix) + else: + self._matrix.fill(0) + + def set(self, y: int, x: int, rgb: tuple): + """ + Method to allow a slice to set an RGB tuple + + :param y: Row + :type y: int + + :param x: Column + :type x: int + + :param rgb: RGB tuple + :type rgb: tuple + + :raises AssertionError: If key is invalid + """ + self.__setitem__((y, x), rgb) + + def get(self, y: int, x: int) -> list: + """ + Method to allow a slice to get an RGB tuple + + :param y: Row + :type y: int + + :param x: Column + :type x: int + + :return rgb: RGB tuple + :return rgb: tuple + + :raises AssertionError: If key is invalid + """ + return self.__getitem__((y, x)) + + def row_binary(self, row_id: int) -> bytes: + """ + Get binary payload for 1 row which is compatible with the driver + + :param row_id: Row ID + :type row_id: int + + :return: Binary payload + :rtype: bytes + """ + assert 0 <= row_id < self._rows, "Row out of bounds" + + start = 0 + end = self._cols - 1 + + return row_id.to_bytes(1, byteorder='big') + start.to_bytes(1, byteorder='big') + end.to_bytes(1, byteorder='big') + self._matrix[:, row_id].tobytes(order='F') + + def to_binary(self): + """ + Get the whole binary for the keyboard to be sent to the driver. + + :return: Driver binary payload + :rtype: bytes + """ + return bytes(self) + + # Simple FB + def to_framebuffer(self): + self._fb1 = _np.copy(self._matrix) + + def to_framebuffer_or(self): + self._fb1 = _np.bitwise_or(self._fb1, self._matrix) # pylint: disable=no-member + + def draw_with_fb_or(self): + self._matrix = _np.bitwise_or(self._fb1, self._matrix) # pylint: disable=no-member + return bytes(self) diff --git a/openrazer/pylib/openrazer/client/macro.py b/openrazer/pylib/openrazer/client/macro.py new file mode 100644 index 00000000..01a5f375 --- /dev/null +++ b/openrazer/pylib/openrazer/client/macro.py @@ -0,0 +1,174 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +import json as _json + +import dbus as _dbus + +import openrazer_daemon.misc.macro as _daemon_macro +from openrazer_daemon import keyboard + + +class RazerMacro(object): + def __init__(self, serial: str, devname: str, daemon_dbus=None, capabilities=None): + if daemon_dbus is None: + session_bus = _dbus.SessionBus() + daemon_dbus = session_bus.get_object("org.razer", "/org/razer/device/{0}".format(serial)) + + if capabilities is None: + self._capabilities = {} + else: + self._capabilities = capabilities + + self._macro_dbus = _dbus.Interface(daemon_dbus, "razer.device.macro") + + self._macro_enabled = False + + self.name = devname + + def get_macros(self) -> dict: + json_payload = self._macro_dbus.getMacros() + macro_structure = _json.loads(json_payload) + + macro_key_mapping = {} + for bind_key, macro_list in macro_structure.items(): + macro_objects = [] + for macro_dict in macro_list: + macro_obj = _daemon_macro.macro_dict_to_obj(macro_dict) + macro_objects.append(macro_obj) + + macro_key_mapping[bind_key] = macro_objects + + return macro_key_mapping + + def add_macro(self, bind_key: str, macro_object_sequence: list): + """ + Add macro to specified bind key + + :param bind_key: Bind Key (has to be in openrazer.keyboard.KEY_MAPPING) + :type bind_key: str + + :param macro_object_sequence: List of macro objects + :type macro_object_sequence: list or tuple or __daemon_macro.MacroObject + """ + if isinstance(macro_object_sequence, _daemon_macro.MacroObject): + macro_object_sequence = [macro_object_sequence] + if not isinstance(macro_object_sequence, (tuple, list)): + raise ValueError("macro_object_sequence is not iterable") + + macro_list = [] + for macro_obj in macro_object_sequence: + if not isinstance(macro_obj, _daemon_macro.MacroObject): + raise ValueError("{0} is not a macro object".format(str(macro_obj))) + + macro_list.append(macro_obj.to_dict()) + + json_payload = _json.dumps(macro_list) + self._macro_dbus.addMacro(bind_key, json_payload) + + def del_macro(self, bind_key: str): + key_map = keyboard.KEY_MAPPING + map_str = "keyboard.KEY_MAPPING" + if self.name in ["Razer Orbweaver", "Razer Orbweaver Chroma", "Razer Tartarus V2", "Razer Tartarus Chroma V2"]: + key_map = keyboard.ORBWEAVER_KEY_MAPPING + map_str = "keyboard.ORBWEAVER_KEY_MAPPING" + elif self.name in ["Razer Tartarus", "Razer Tartarus Chroma", "Razer Nostromo"]: + key_map = keyboard.TARTARUS_KEY_MAPPING + map_str = "keyboard.TARTARUS_KEY_MAPPING" + elif self.name in ["Razer Naga Hex V2", "Razer Naga Chroma"]: + key_map = keyboard.NAGA_HEX_V2_KEY_MAPPING + map_str = "keyboard.NAGA_HEX_V2_KEY_MAPPING" + + if bind_key not in key_map: + raise ValueError("Key {0} is not in openrazer.{1}".format(bind_key, map_str)) + else: + self._macro_dbus.deleteMacro(bind_key) + + @property + def mode_modifier(self): + if 'macro_mode_modifier' in self._capabilities: + return self._macro_dbus.getModeModifier() + return False + + @mode_modifier.setter + def mode_modifier(self, value): + if 'macro_mode_modifier' in self._capabilities and isinstance(value, bool): + self._macro_dbus.getModeModifier(value) + + @staticmethod + def create_url_macro_item(url: str) -> _daemon_macro.MacroURL: + """ + Create a macro object that opens a URL in a browser + + :param url: URL + :type url: str + + :return: Macro object + :rtype: _daemon_macro.MacroURL + """ + return _daemon_macro.MacroURL(url) + + @staticmethod + def create_script_macro_item(script_path: str, script_args: str = None) -> _daemon_macro.MacroScript: + """ + Create a macro object that runs a script + + The arguments to the script should be a string containing all the arguments, if any values contain spaces they should be quoted accordingly + :param script_path: Script filepath, includes script name + :type script_path: str + + :param script_args: Script arguments + :type script_args: str or None + + :return: Macro object + :rtype: _daemon_macro.MacroScript + """ + return _daemon_macro.MacroScript(script_path, script_args) + + @staticmethod + def create_keypress_up_macro_item(key_name: str, pre_pause: int = 0) -> _daemon_macro.MacroKey: + """ + Create a macro action that consists of a key release event + + :param key_name: Key Name, compatible with XTE + :type key_name: str + + :param pre_pause: Optional delay before key is actioned (if turned on in daemon) + :type pre_pause: int + + :return: Macro Key + :rtype: _daemon_macro.MacroKey + """ + return _daemon_macro.MacroKey(key_name, pre_pause, 'UP') + + @staticmethod + def create_keypress_down_macro_item(key_name: str, pre_pause: int = 0) -> _daemon_macro.MacroKey: + """ + Create a macro action that consists of a key press event + + :param key_name: Key Name, compatible with XTE + :type key_name: str + + :param pre_pause: Optional delay before key is actioned (if turned on in daemon) + :type pre_pause: int + + :return: Macro Key + :rtype: _daemon_macro.MacroKey + """ + return _daemon_macro.MacroKey(key_name, pre_pause, 'DOWN') + + @classmethod + def create_keypress_macro_item(cls, key_name: str, pre_pause: int = 0) -> list: + """ + Create a macro action that consists of a key press and release event + + The pre_pause delay will be applied to both key events + :param key_name: Key Name, compatible with XTE + :type key_name: str + + :param pre_pause: Optional delay before key is actioned (if turned on in daemon) + :type pre_pause: int + + :return: Macro Key + :rtype: list of _daemon_macro.MacroKey + """ + return [cls.create_keypress_down_macro_item(key_name, pre_pause), cls.create_keypress_up_macro_item(key_name, pre_pause)] diff --git a/openrazer/pylib/setup.py b/openrazer/pylib/setup.py new file mode 100644 index 00000000..700fb2f4 --- /dev/null +++ b/openrazer/pylib/setup.py @@ -0,0 +1,28 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +from setuptools import setup, find_packages + +setup( + name="openrazer", + version="3.10.3", + packages=find_packages(exclude=["tests", "openrazer._fake_driver"]), + install_requires=[ + "dbus-python >= 1.2.0", + "numpy >= 1.11.0", + "openrazer_daemon == 3.10.3", + ], + author="OpenRazer contributors", + description="Library for interacting with the OpenRazer daemon.", + license="GPLv2+", + url="https://openrazer.github.io/", + project_urls={ + "Bug Tracker": "https://github.com/openrazer/openrazer/issues", + "Source Code": "https://github.com/openrazer/openrazer/tree/master/pylib", + }, + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", + "Operating System :: POSIX :: Linux", + ], +) diff --git a/openrazer/pylib/tests/integration_tests/test_device_manager.py b/openrazer/pylib/tests/integration_tests/test_device_manager.py new file mode 100755 index 00000000..b7abdbbf --- /dev/null +++ b/openrazer/pylib/tests/integration_tests/test_device_manager.py @@ -0,0 +1,346 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +import multiprocessing +import os +import signal +import tempfile +import time +import unittest +import shutil +import openrazer.client +import openrazer_daemon.daemon +import openrazer._fake_driver as fake_driver + + +def run_daemon(daemon_dir, driver_dir): + # TODO console_log false + daemon = openrazer_daemon.daemon.RazerDaemon(verbose=True, console_log=False, test_dir=driver_dir) + daemon.run() + + +class DeviceManagerTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls._daemon_dir = tempfile.mkdtemp(prefix='tmp_', suffix='_daemondata') + cls._tmp_dir = tempfile.mkdtemp(prefix='tmp_', suffix='_daemontest') + + cls._bw_serial = 'IO0000000000001' + cls._bw_chroma = fake_driver.FakeDevice('razerblackwidowchroma', serial=cls._bw_serial, tmp_dir=cls._tmp_dir) + print("Created BlackWidow Chroma endpoints") + + cls._daemon_proc = multiprocessing.Process(target=run_daemon, args=(cls._daemon_dir, cls._tmp_dir)) + cls._daemon_proc.start() + print("Started daemon") + time.sleep(5) + + @classmethod + def tearDownClass(cls): + print("Stopping daemon") + os.kill(cls._daemon_proc.pid, signal.SIGINT) + time.sleep(3) + if cls._daemon_proc.is_alive(): + print("Daemon still alive...") + time.sleep(8) + if cls._daemon_proc.is_alive(): + cls._daemon_proc.terminate() + + if cls._daemon_proc.is_alive(): + print("Failed to kill daemon") + + cls._bw_chroma.close() + + shutil.rmtree(cls._tmp_dir) + shutil.rmtree(cls._daemon_dir) + + time.sleep(5) + + def setUp(self): + self._bw_chroma.create_endpoints() + + self.device_manager = openrazer.client.DeviceManager() + + def test_device_list(self): + self.assertEqual(len(self.device_manager.devices), 1) + + def test_serial(self): + device = self.device_manager.devices[0] + + self.assertEqual(device.serial, self._bw_chroma.get('device_serial')) + + def test_name(self): + device = self.device_manager.devices[0] + + self.assertEqual(device.name, self._bw_chroma.get('device_type')) + + def test_type(self): + device = self.device_manager.devices[0] + + self.assertEqual(device.type, 'keyboard') + + def test_fw_version(self): + device = self.device_manager.devices[0] + + self.assertEqual(device.firmware_version, self._bw_chroma.get('firmware_version')) + + def test_brightness(self): + device = self.device_manager.devices[0] + + # Test 100% + device.brightness = 100.0 + + self.assertEqual('255', self._bw_chroma.get('matrix_brightness')) + + self.assertEqual(100.0, device.brightness) + + device.brightness = 50.0 + + self.assertEqual('127', self._bw_chroma.get('matrix_brightness')) + + self.assertAlmostEqual(50.0, device.brightness, delta=0.4) + + device.brightness = 0.0 + + self.assertEqual('0', self._bw_chroma.get('matrix_brightness')) + + self.assertEqual(0, device.brightness) + + def test_capabilities(self): + device = self.device_manager.devices[0] + + self.assertEqual(device.capabilities, device._capabilities) + + def test_device_keyboard_game_mode(self): + device = self.device_manager.devices[0] + + self._bw_chroma.set('mode_game', '1') + self.assertTrue(device.game_mode_led) + device.game_mode_led = False + self.assertEqual(self._bw_chroma.get('mode_game'), '0') + device.game_mode_led = True + self.assertEqual(self._bw_chroma.get('mode_game'), '1') + + def test_device_keyboard_macro_mode(self): + device = self.device_manager.devices[0] + + self._bw_chroma.set('mode_macro', '1') + self.assertTrue(device.macro_mode_led) + device.macro_mode_led = False + self.assertEqual(self._bw_chroma.get('mode_macro'), '0') + device.macro_mode_led = True + self.assertEqual(self._bw_chroma.get('mode_macro'), '1') + + self._bw_chroma.set('mode_macro_effect', '0') + self.assertEqual(device.macro_mode_led_effect, openrazer.client.constants.MACRO_LED_STATIC) + device.macro_mode_led_effect = openrazer.client.constants.MACRO_LED_BLINK + self.assertEqual(self._bw_chroma.get('mode_macro'), str(openrazer.client.constants.MACRO_LED_BLINK)) + + def test_device_keyboard_effect_none(self): + device = self.device_manager.devices[0] + + device.fx.none() + + self.assertEqual(self._bw_chroma.get('matrix_effect_none'), '1') + + def test_device_keyboard_effect_spectrum(self): + device = self.device_manager.devices[0] + + device.fx.spectrum() + + self.assertEqual(self._bw_chroma.get('matrix_effect_spectrum'), '1') + + def test_device_keyboard_effect_wave(self): + device = self.device_manager.devices[0] + + device.fx.wave(openrazer.client.constants.WAVE_LEFT) + self.assertEqual(self._bw_chroma.get('matrix_effect_wave'), str(openrazer.client.constants.WAVE_LEFT)) + device.fx.wave(openrazer.client.constants.WAVE_RIGHT) + self.assertEqual(self._bw_chroma.get('matrix_effect_wave'), str(openrazer.client.constants.WAVE_RIGHT)) + + with self.assertRaises(ValueError): + device.fx.wave('lalala') + + def test_device_keyboard_effect_wheel(self): + device = self.device_manager.devices[0] + + device.fx.wheel(openrazer.client.constants.WHEEL_LEFT) + self.assertEqual(self._bw_chroma.get('matrix_effect_wheel'), str(openrazer.client.constants.WHEEL_LEFT)) + device.fx.wheel(openrazer.client.constants.WHEEL_RIGHT) + self.assertEqual(self._bw_chroma.get('matrix_effect_wheel'), str(openrazer.client.constants.WHEEL_RIGHT)) + + with self.assertRaises(ValueError): + device.fx.wheel('lalala') + + def test_device_keyboard_effect_static(self): + device = self.device_manager.devices[0] + + device.fx.static(255, 0, 255) + self.assertEqual(b'\xFF\x00\xFF', self._bw_chroma.get('matrix_effect_static', binary=True)) + + for red, green, blue in ((256.0, 0, 0), (0, 256.0, 0), (0, 0, 256.0)): + with self.assertRaises(ValueError): + device.fx.static(red, green, blue) + + device.fx.static(256, 0, 700) + self.assertEqual(b'\xFF\x00\xFF', self._bw_chroma.get('matrix_effect_static', binary=True)) + + def test_device_keyboard_effect_reactive(self): + device = self.device_manager.devices[0] + + time = openrazer.client.constants.REACTIVE_500MS + device.fx.reactive(255, 0, 255, time) + self.assertEqual(b'\x01\xFF\x00\xFF', self._bw_chroma.get('matrix_effect_reactive', binary=True)) + + for red, green, blue in ((256.0, 0, 0), (0, 256.0, 0), (0, 0, 256.0)): + with self.assertRaises(ValueError): + device.fx.reactive(red, green, blue, time) + + device.fx.reactive(256, 0, 700, time) + self.assertEqual(b'\x01\xFF\x00\xFF', self._bw_chroma.get('matrix_effect_reactive', binary=True)) + + with self.assertRaises(ValueError): + device.fx.reactive(255, 0, 255, 'lalala') + + def test_device_keyboard_effect_breath_single(self): + device = self.device_manager.devices[0] + + device.fx.breath_single(255, 0, 255) + self.assertEqual(b'\xFF\x00\xFF', self._bw_chroma.get('matrix_effect_breath', binary=True)) + + for red, green, blue in ((256.0, 0, 0), (0, 256.0, 0), (0, 0, 256.0)): + with self.assertRaises(ValueError): + device.fx.breath_single(red, green, blue) + + device.fx.breath_single(256, 0, 700) + self.assertEqual(b'\xFF\x00\xFF', self._bw_chroma.get('matrix_effect_breath', binary=True)) + + def test_device_keyboard_effect_breath_dual(self): + device = self.device_manager.devices[0] + + device.fx.breath_dual(255, 0, 255, 255, 0, 0) + self.assertEqual(b'\xFF\x00\xFF\xFF\x00\x00', self._bw_chroma.get('matrix_effect_breath', binary=True)) + + for r1, g1, b1, r2, g2, b2 in ((256.0, 0, 0, 0, 0, 0), (0, 256.0, 0, 0, 0, 0), (0, 0, 256.0, 0, 0, 0), + (0, 0, 0, 256.0, 0, 0), (0, 0, 0, 0, 256.0, 0), (0, 0, 0, 0, 0, 256.0)): + with self.assertRaises(ValueError): + device.fx.breath_dual(r1, g1, b1, r2, g2, b2) + + device.fx.breath_dual(256, 0, 700, 255, 0, 0) + self.assertEqual(b'\xFF\x00\xFF\xFF\x00\x00', self._bw_chroma.get('matrix_effect_breath', binary=True)) + + def test_device_keyboard_effect_breath_random(self): + device = self.device_manager.devices[0] + + device.fx.breath_random() + + self.assertEqual(self._bw_chroma.get('matrix_effect_breath'), '1') + + def test_device_keyboard_effect_ripple(self): + device = self.device_manager.devices[0] + + refresh_rate = 0.01 + device.fx.ripple(255, 0, 255, refresh_rate) + time.sleep(0.1) + + custom_effect_payload = self._bw_chroma.get('matrix_custom_frame', binary=True) + self.assertGreater(len(custom_effect_payload), 1) + self.assertEqual(self._bw_chroma.get('matrix_effect_custom'), '1') + + for red, green, blue in ((256.0, 0, 0), (0, 256.0, 0), (0, 0, 256.0)): + with self.assertRaises(ValueError): + device.fx.reactive(red, green, blue, refresh_rate) + + with self.assertRaises(ValueError): + device.fx.reactive(255, 0, 255, 'lalala') + + device.fx.none() + + def test_device_keyboard_effect_random_ripple(self): + device = self.device_manager.devices[0] + + refresh_rate = 0.01 + device.fx.ripple_random(refresh_rate) + time.sleep(0.1) + + custom_effect_payload = self._bw_chroma.get('matrix_custom_frame', binary=True) + self.assertGreater(len(custom_effect_payload), 1) + self.assertEqual(self._bw_chroma.get('matrix_effect_custom'), '1') + + with self.assertRaises(ValueError): + device.fx.ripple_random('lalala') + + device.fx.none() + + def test_device_keyboard_effect_framebuffer(self): + device = self.device_manager.devices[0] + + device.fx.advanced.matrix.set(0, 0, (255, 0, 255)) + + self.assertEqual(device.fx.advanced.matrix.get(0, 0), (255, 0, 255)) + + device.fx.advanced.draw() + custom_effect_payload = self._bw_chroma.get('matrix_custom_frame', binary=True) + self.assertEqual(custom_effect_payload[:4], b'\x00\xFF\x00\xFF') + + device.fx.advanced.matrix.to_framebuffer() # Save 255, 0, 255 + device.fx.advanced.matrix.reset() # Clear FB + + device.fx.advanced.matrix.set(0, 0, (0, 255, 0)) + + device.fx.advanced.draw_fb_or() # Draw FB or'd with Matrix + custom_effect_payload = self._bw_chroma.get('matrix_custom_frame', binary=True) + self.assertEqual(custom_effect_payload[:4], b'\x00\xFF\xFF\xFF') + + # Append that to FB + device.fx.advanced.matrix.to_framebuffer_or() + device.fx.advanced.draw() + custom_effect_payload = self._bw_chroma.get('matrix_custom_frame', binary=True) + + binary = device.fx.advanced.matrix.to_binary() + + self.assertEqual(binary, custom_effect_payload) + + def test_device_keyboard_macro_enable(self): + device = self.device_manager.devices[0] + + device.macro.enable_macros() + + self.assertEqual(self._bw_chroma.get('macro_keys'), '1') + + def test_device_keyboard_macro_add(self): + device = self.device_manager.devices[0] + + url_macro = device.macro.create_url_macro_item('http://example.org') + device.macro.add_macro('M1', [url_macro]) + + macros = device.macro.get_macros() + self.assertIn('M1', macros) + + with self.assertRaises(ValueError): + device.macro.add_macro('M6', url_macro) # Unknown key + + with self.assertRaises(ValueError): + device.macro.add_macro('M1', 'lalala') # Not a sequnce + + with self.assertRaises(ValueError): + device.macro.add_macro('M1', ['lalala']) # Bad element in sequence + + def test_device_keyboard_macro_del(self): + device = self.device_manager.devices[0] + + url_macro = device.macro.create_url_macro_item('http://example.org') + device.macro.add_macro('M2', [url_macro]) + + macros = device.macro.get_macros() + self.assertIn('M2', macros) + + device.macro.del_macro('M2') + macros = device.macro.get_macros() + self.assertNotIn('M2', macros) + + with self.assertRaises(ValueError): + device.macro.del_macro('M6') # Unknown key + + +if __name__ == "__main__": + unittest.main() diff --git a/openrazer/scripts/build_debs.sh b/openrazer/scripts/build_debs.sh new file mode 100755 index 00000000..d40d68d3 --- /dev/null +++ b/openrazer/scripts/build_debs.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +RED='\033[0;31m' +GREEN='\033[1;32m' +BLUE='\033[0;37m' +NC='\033[0m' + +TEMP_DIR=$(mktemp --suffix="_deb_build_tmp" -d) +ROOT="$(git rev-parse --show-toplevel)" + +echo -e "${BLUE}Temp DIR: ${TEMP_DIR}${NC}" + +echo -e "${BLUE}Copying source to temporary build directory${NC}" + +# Go to root of directory +cd "${ROOT}" + +# Extract version from changelog +VERSION=$(cat "${ROOT}/debian/changelog" | grep -m 1 -oP '(?<=openrazer \()[^\-\)]+') +ORIG_TAR="openrazer_${VERSION}.orig.tar.gz" + +# Add a -0 revision to changelog for building +sed -i 's|'$VERSION')|'$VERSION'-0)|' "${ROOT}/debian/changelog" + +#git archive ${CURRENT_BRANCH} | gzip > ${TEMP_DIR}/${ORIG_TAR} +tar --exclude-vcs --exclude-vcs-ignores -zcf ${TEMP_DIR}/${ORIG_TAR} -C "${ROOT}" . + + +cd ${TEMP_DIR} +mkdir razer +tar xf ${ORIG_TAR} -C razer +cd razer +echo -e "${BLUE}Building deb packages${NC}\n" +dpkg-buildpackage -us -uc > ${TEMP_DIR}/build.log 2>&1 +result_code=$? + +cd "${CWD}" + +if [ $result_code = 0 ]; then + echo -e "${GREEN}Deb packages build successfully. Copied to ./dist/${NC}" + mkdir -p "${ROOT}/dist/" + cp ${TEMP_DIR}/*.deb "${ROOT}/dist/" + +else + echo -e "${RED}Failed to generate deb files. Check ${TEMP_DIR}/build.log for more details${NC}" +fi + +# Add a -0 revision to changelog for building +sed -i 's|'$VERSION'-0)|'$VERSION')|' "${ROOT}/debian/changelog" + diff --git a/openrazer/scripts/build_source_debs.sh b/openrazer/scripts/build_source_debs.sh new file mode 100755 index 00000000..d8e31015 --- /dev/null +++ b/openrazer/scripts/build_source_debs.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +RED='\033[0;31m' +GREEN='\033[1;32m' +BLUE='\033[0;37m' +NC='\033[0m' + +TEMP_DIR=$(mktemp --suffix="_deb_build_tmp" -d) +ROOT=$(git rev-parse --show-toplevel) + +echo -e "${BLUE}Temp DIR: ${TEMP_DIR}${NC}" + +echo -e "${BLUE}Copying source to temporary build directory${NC}" + +# Go to root of directory +cd "${ROOT}" + +# Extract version from changelog +VERSION=$(cat "${ROOT}/debian/changelog" | grep -m 1 -oP '(?<=openrazer \()[^\-\)]+') +ORIG_TAR="openrazer_${VERSION}.orig.tar.gz" + +#git archive ${CURRENT_BRANCH} | gzip > ${TEMP_DIR}/${ORIG_TAR} +tar --exclude-vcs --exclude-vcs-ignores -zcf ${TEMP_DIR}/${ORIG_TAR} -C "${ROOT}" . + + +cd ${TEMP_DIR} +mkdir razer +tar xf ${ORIG_TAR} -C razer +cd razer +echo -e "${BLUE}Building deb packages${NC}\n" +debuild -S > ${TEMP_DIR}/build.log 2>&1 +result_code=$? + + +cd "${CWD}" + +if [ $result_code = 0 ]; then + echo -e "${GREEN}Source Deb packages build successfully. Running pbuilder${NC}" + sudo pbuilder --build --distribution xenial --architecture amd64 --basetgz /var/cache/pbuilder/xenial-amd64-base.tgz ${TEMP_DIR}/razer_${VERSION}*.dsc + echo -e "${BLUE}Temp DIR: ${TEMP_DIR}${NC}" +else + echo -e "${RED}Failed to generate deb files. Check ${TEMP_DIR}/build.log for more details${NC}" +fi + diff --git a/openrazer/scripts/ci/check-astyle-formatting.sh b/openrazer/scripts/ci/check-astyle-formatting.sh new file mode 100755 index 00000000..abd9f1a3 --- /dev/null +++ b/openrazer/scripts/ci/check-astyle-formatting.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Installation: +# cd my_gitproject +# wget -O pre-commit.sh http://tinyurl.com/mkovs45 +# ln -s ../../pre-commit.sh .git/hooks/pre-commit +# chmod +x pre-commit.sh + +# Modified for the OpenRazer CI. + +OPTIONS="--style=linux" + +RETURN=0 +ASTYLE=$(which astyle) +if [ $? -ne 0 ]; then + echo "[!] astyle not installed. Unable to check source file format policy." >&2 + exit 1 +fi + +FILES=`find driver/ -name "*.c" -o -name "*.h"` +for FILE in $FILES; do + $ASTYLE $OPTIONS < $FILE | cmp -s $FILE - + if [ $? -ne 0 ]; then + echo "[!] $FILE does not respect the agreed coding style." >&2 + RETURN=1 + fi +done + +if [ $RETURN -eq 1 ]; then + echo "" >&2 + echo "You can run ./scripts/format_source.sh to automatically format those files." >&2 +fi + +exit $RETURN diff --git a/openrazer/scripts/ci/check-autopep8-formatting.sh b/openrazer/scripts/ci/check-autopep8-formatting.sh new file mode 100755 index 00000000..4d5b6cd7 --- /dev/null +++ b/openrazer/scripts/ci/check-autopep8-formatting.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +OPTIONS="--max-line-length 500 --ignore E402" + +RETURN=0 +AUTOPEP8=$(which autopep8) +if [ $? -ne 0 ]; then + echo "[!] autopep8 not installed. Unable to check source file format policy." >&2 + exit 1 +fi + +FILES=$(find . -name "*.py") +for FILE in $FILES; do + DIFF=$($AUTOPEP8 $OPTIONS $FILE | diff -u $FILE -) + if [ $? -ne 0 ]; then + echo "[!] $FILE does not respect the agreed coding style." >&2 + echo "$DIFF" >&2 + RETURN=1 + fi +done + +if [ $RETURN -eq 1 ]; then + echo "" >&2 + echo "You can run ./scripts/format_source.sh to automatically format those files." >&2 +fi + +exit $RETURN diff --git a/openrazer/scripts/ci/check-pylint.sh b/openrazer/scripts/ci/check-pylint.sh new file mode 100755 index 00000000..05d6770f --- /dev/null +++ b/openrazer/scripts/ci/check-pylint.sh @@ -0,0 +1,3 @@ +#!/bin/bash -e + +find . -name "*.py" | xargs pylint --errors-only diff --git a/openrazer/scripts/ci/launch-daemon.sh b/openrazer/scripts/ci/launch-daemon.sh new file mode 100755 index 00000000..37f4feb5 --- /dev/null +++ b/openrazer/scripts/ci/launch-daemon.sh @@ -0,0 +1,17 @@ +#!/bin/bash -ex + +#env PYTHONPATH="pylib:daemon" \ +#python3 ./daemon/run_openrazer_daemon.py \ +# --verbose \ +# --foreground \ +# --config=$(pwd)/daemon/resources/razer.conf \ +# --as-root & + +env PYTHONPATH="pylib:daemon" \ +python3 ./daemon/run_openrazer_daemon.py \ + --foreground \ + --run-dir /tmp/daemon_stuff/data \ + --log-dir /tmp/daemon_stuff/logs \ + --test-dir /tmp/daemon_test \ + --config=$(pwd)/daemon/resources/razer.conf \ + --as-root & diff --git a/openrazer/scripts/ci/setup-fakedriver.sh b/openrazer/scripts/ci/setup-fakedriver.sh new file mode 100755 index 00000000..fc4f0f39 --- /dev/null +++ b/openrazer/scripts/ci/setup-fakedriver.sh @@ -0,0 +1,11 @@ +#!/bin/bash -ex + +mkdir /tmp/daemon_stuff/{,data,logs} +mkdir /tmp/daemon_test +./scripts/create_fake_device.py \ + --dest /tmp/daemon_test \ + --non-interactive \ + --all & + +# wait a bit for the previous script to settle +sleep 0.5 diff --git a/openrazer/scripts/ci/test-auto-generate.sh b/openrazer/scripts/ci/test-auto-generate.sh new file mode 100755 index 00000000..31f0fb07 --- /dev/null +++ b/openrazer/scripts/ci/test-auto-generate.sh @@ -0,0 +1,27 @@ +#!/bin/bash -e + +./scripts/generate_appstream_file.sh +if [ -n "$(git diff)" ]; then + echo + echo "ERROR: Appstream file needs to be regenerated!" + echo + git diff + echo + echo "Please run './scripts/generate_appstream_file.sh'" + echo + exit 1 +fi + +./scripts/generate_all_fake_drivers.sh -f +git add --intent-to-add ./pylib/openrazer/_fake_driver/ +if [ -n "$(git diff)" ]; then + echo + echo "ERROR: Fake driver files needs to be regenerated!" + echo + git diff + echo + echo "Please run './scripts/generate_all_fake_drivers.sh -f'" + echo "Note that this will delete all existing fake driver files." + echo + exit 1 +fi diff --git a/openrazer/scripts/ci/test-daemon.py b/openrazer/scripts/ci/test-daemon.py new file mode 100755 index 00000000..f40260c2 --- /dev/null +++ b/openrazer/scripts/ci/test-daemon.py @@ -0,0 +1,155 @@ +#!/usr/bin/python3 +import openrazer.client +import glob + +daemon_test_dir = "/tmp/daemon_test" +devmgr = openrazer.client.DeviceManager() +passed = True + + +def _test_failed(name, msg): + global passed + passed = False + print(f"\nFAILED: {name}\n ", msg) + + +def test_sanity_check_matrix_capabilities(d): + if d.has("lighting_led_matrix"): + d.fx.advanced.matrix[0, 0] = [0, 255, 0] + try: + d.fx.advanced.draw() + except Exception as e: + _test_failed(d.name, e) + + +def test_wired_wireless_naming(): + # Enforce the (Wired) or (Wireless) suffix naming convention when devices have multiple PIDs + device_names = list(map(lambda device: device.name, devmgr.devices)) + + for name in device_names: + if name.find("(Wired)") != -1: + striped_name = name.replace("(Wired)", "").strip() + if striped_name in device_names: + _test_failed(striped_name, "Naming pattern is inconsistent. Append \"(Wireless)\" for the other USB PID.") + + elif name.find("(Wireless)") != -1: + striped_name = name.replace("(Wireless)", "").strip() + if striped_name in device_names: + _test_failed(striped_name, "Naming pattern is inconsistent. Append \"(Wired)\" for the other USB PID.") + + +def test_sysfs_consistency(d): + # Check sysfs files exist for capabilities + vid = str(hex(d._vid))[2:].upper().rjust(4, '0') + pid = str(hex(d._pid))[2:].upper().rjust(4, '0') + + def check_sysfs(capability: str, sysfs_name: str): + """ + Check the device has either the given pylib capability for the + given sysfs name, and vice versa. + """ + try: + expected_path = glob.glob(f"{daemon_test_dir}/*:{vid}:{pid}*/{sysfs_name}", recursive=True)[0] + except IndexError: + expected_path = "" + + if d.has(capability) and not glob.glob(expected_path, recursive=True): + _test_failed(d.name, str(hex(d._pid)) + " Has capability '{}' but no sysfs file: '{}'".format(capability, sysfs_name)) + + if not d.has(capability) and glob.glob(expected_path, recursive=True): + _test_failed(d.name, str(hex(d._pid)) + " Has sysfs '{}' but no capability set: '{}'".format(sysfs_name, capability)) + + def check_any_sysfs(capabilities: list[str], sysfs_names: list[str]): + """ + Check the device has one of these sysfs names for one of these pylib capabilities. + """ + found_sysfs = [] + found_capability = [] + + for sysfs_name in sysfs_names: + if glob.glob(f"{daemon_test_dir}/*:{vid}:{pid}*/{sysfs_name}", recursive=True): + found_sysfs.append(sysfs_name) + + for capability in capabilities: + if d.has(capability): + found_capability.append(capability) + + # Skip Razer devices that have non-RGB effects + if not found_capability and ("logo_led_effect" in sysfs_names or "scroll_led_effect" in sysfs_names): + return + + if not found_capability and found_sysfs: + _test_failed(d.name, str(hex(d._pid)) + " Has one of these sysfs {} but none of these capabilities: {}".format(sysfs_names, capabilities)) + + if found_capability and not found_sysfs: + _test_failed(d.name, str(hex(d._pid)) + " Has one of these capabilities {} but none of these sysfs files: {}".format(capabilities, sysfs_names)) + + # check_sysfs("battery", "charge_effect") # FIXME this is not correct, as per PR comments + check_sysfs("set_low_battery_threshold", "charge_low_threshold") # deprecated + check_sysfs("low_battery_threshold", "charge_low_threshold") + check_sysfs("set_idle_time", "device_idle_time") # deprecated + check_sysfs("idle_time", "device_idle_time") + + check_sysfs("battery", "charge_level") + check_sysfs("battery", "charge_status") + check_sysfs("brightness", "matrix_brightness") + check_sysfs("dpi", "dpi") + check_sysfs("dpi_stages", "dpi_stages") + check_sysfs("firmware_version", "firmware_version") + check_sysfs("game_mode_led", "game_led_state") + check_sysfs("macro_mode_led", "macro_led_state") + check_sysfs("macro_mode_led_effect", "macro_led_effect") + check_sysfs("poll_rate", "poll_rate") + check_sysfs("serial", "device_serial") + check_sysfs("type", "device_type") + + if d.type == "keyboard": + check_sysfs("keyboard_layout", "kbd_layout") + + # Devices with a matrix defined should have a suitable "custom" sysfs. Krakens are a special case. + if d._matrix_dimensions != (-1, -1) and d.name.find("Kraken") == -1: + check_sysfs("lighting_led_matrix", "matrix_custom_frame") + check_sysfs("lighting_led_matrix", "matrix_effect_custom") + + check_sysfs("lighting_breath_single", "matrix_effect_breath") + check_sysfs("lighting_none", "matrix_effect_none") + check_sysfs("lighting_reactive", "matrix_effect_reactive") + check_sysfs("reactive_trigger", "matrix_reactive_trigger") + check_sysfs("lighting_spectrum", "matrix_effect_spectrum") + check_any_sysfs(["lighting_starlight_random", "lighting_starlight_single", "lighting_starlight_dual"], ["matrix_effect_starlight"]) + # Ignore devices that have mono-color razer.device.lighting.bw2013.setStatic() + if d._pid not in [0x010d, 0x010e, 0x0113, 0x0118, 0x011a, 0x011b, 0x011c, 0x0202]: + check_sysfs("lighting_static", "matrix_effect_static") + check_sysfs("lighting_wave", "matrix_effect_wave") + check_sysfs("lighting_wheel", "matrix_effect_wheel") + check_sysfs("lighting_pulsate", "matrix_effect_pulsate") + check_sysfs("lighting_blinking", "matrix_effect_blinking") + + check_sysfs("lighting_backlight_active", "backlight_led_state") + + for prefix in ["logo", "scroll", "left", "right", "charging", "fast_charging", "fully_charged"]: + check_sysfs(f"lighting_{prefix}_brightness", f"{prefix}_led_brightness") + check_sysfs(f"lighting_{prefix}_active", f"{prefix}_led_state") + + for effect in ["none", "reactive", "spectrum", "static", "wave"]: + # There are two implementations with different sysfs files + check_any_sysfs([f"lighting_{prefix}_{effect}"], [f"{prefix}_matrix_effect_{effect}", f"{prefix}_led_effect"]) + + check_any_sysfs([f"lighting_{prefix}_breath_single", f"lighting_{prefix}_breath_mono"], [f"{prefix}_matrix_effect_breath"]) + + +def test_ripple_capable(d): + # Check that the device has a matrix for a software ripple effect + if d.has("lighting_ripple") or d.has("lighting_ripple_random"): + if d._matrix_dimensions == (-1, -1): + _test_failed(d.name, "Cannot have a ripple capability without a matrix") + + +for d in devmgr.devices: + test_sanity_check_matrix_capabilities(d) + test_sysfs_consistency(d) + test_ripple_capable(d) +test_wired_wireless_naming() + +if not passed: + exit(1) diff --git a/openrazer/scripts/ci/test-daemon.sh b/openrazer/scripts/ci/test-daemon.sh new file mode 100755 index 00000000..df0bc931 --- /dev/null +++ b/openrazer/scripts/ci/test-daemon.sh @@ -0,0 +1,16 @@ +#!/bin/bash -ex + +all_devices=$(ls pylib/openrazer/_fake_driver/*.cfg | wc -l) + +daemon_devices=$(PYTHONPATH="pylib:daemon" python3 -c "from openrazer.client import DeviceManager; mgr = DeviceManager(); print(len(mgr.devices))") + +if [ "$all_devices" != "$daemon_devices" ]; then + echo + echo "Unexpected discrepancy between devices in fake driver and devices from daemon:" + echo "$all_devices != $daemon_devices" + echo + exit 1 +fi + +PYTHONPATH="pylib:daemon" python3 scripts/ci/test-daemon.py +PYTHONPATH="pylib:daemon" python3 scripts/ci/test-pids.py diff --git a/openrazer/scripts/ci/test-hex-casing.sh b/openrazer/scripts/ci/test-hex-casing.sh new file mode 100755 index 00000000..7d73417c --- /dev/null +++ b/openrazer/scripts/ci/test-hex-casing.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Checks for correct casing of hex values in the source + +out=$(grep -rh "USB_PID = " daemon/openrazer_daemon/hardware/ | cut -d '=' -f2 | grep -v None | sort -f | grep -E '[a-f]') + +if [ ! -z "$out" ]; then + echo "ERROR: wrong casing of hex number!" + echo "Please convert the following hex numbers in daemon/openrazer_daemon/hardware/ to uppercase:" + echo "$out" + exit 1 +fi + +out=$(git grep "#define USB_DEVICE_ID_" driver/ | cut -d' ' -f3 | sort -f | grep -E '[a-f]') + +if [ ! -z "$out" ]; then + echo "ERROR: wrong casing of hex number!" + echo "Please convert the following hex numbers in driver/ to uppercase:" + echo "$out" + exit 1 +fi + +echo "No issues found." diff --git a/openrazer/scripts/ci/test-pids.py b/openrazer/scripts/ci/test-pids.py new file mode 100755 index 00000000..afa3cc3a --- /dev/null +++ b/openrazer/scripts/ci/test-pids.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +""" +Checks other files in the repository are consistent. +- Ensure PID is documented in README for end users. +- Ensure PID is added for udev rules so permissions work. +""" +import os +import openrazer.client + +repo_root = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "..")) +devmgr = openrazer.client.DeviceManager() +passed = True + +# Files containing PIDs +with open(f"{repo_root}/README.md") as f: + README = f.readlines() + +with open(f"{repo_root}/install_files/udev/99-razer.rules") as f: + UDEV = f.readlines() + +for device in devmgr.devices: + pid_upper = str(hex(device._pid))[2:].upper().rjust(4, '0') + pid_lower = pid_upper.lower() + found_readme = False + found_udev = False + + for line in README: + if pid_upper != pid_lower and line.find(pid_lower) > 0: + print(f"Warning: Found lowercase pid {pid_lower} in README.md, should be uppercase!") + if line.find(pid_upper) > 0: + found_readme = True + break + + for line in UDEV: + if pid_upper != pid_lower and line.find(pid_upper) > 0: + print(f"Warning: Found uppercase pid {pid_upper} in 99-razer.rules, should be lowercase!") + if line.find(pid_lower) > 0: + found_udev = True + break + + if not found_readme: + print(f"\nMissing from README: {device.name} ({pid_upper})") + passed = False + + if not found_udev: + print(f"\nMissing from 99-razer.rules: {device.name} ({pid_lower})") + passed = False + +if not passed: + exit(1) diff --git a/openrazer/scripts/create_fake_device.py b/openrazer/scripts/create_fake_device.py new file mode 100755 index 00000000..19ce56af --- /dev/null +++ b/openrazer/scripts/create_fake_device.py @@ -0,0 +1,250 @@ +#!/usr/bin/python3 +import argparse +import atexit +import cmd +import os +import shutil +import sys +import tempfile +import time + +PYLIB = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'pylib') +sys.path.insert(1, PYLIB) + +import openrazer._fake_driver as fake_driver + + +class FakeDevicePrompt(cmd.Cmd): + + def __init__(self, device_map, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._device_map = device_map + self._current_device = None + + self._ep = {} + self._read = [] + self._write = [] + + # If only 1 device, auto use that + if len(self._device_map) == 1: + self._change_device(list(self._device_map.keys())[0]) + else: + self._change_device(None) + + def _change_device(self, device_name=None): + if device_name is not None: + self._current_device = device_name + self.prompt = self._current_device + "> " + + for endpoint, details in self._device_map[self._current_device].endpoints.items(): + self._ep[endpoint] = details[2] + + self._read = [endpoint for endpoint, perm in self._ep.items()] + self._write = [endpoint for endpoint, perm in self._ep.items() if perm in ('w', 'rw')] + else: + self._current_device = None + self.prompt = "> " + + def do_dev(self, arg): + """ + Change current device + """ + if arg in self._device_map: + if arg is None or len(arg) == 0: + print('Need to specify a device name. One of: {0}'.format(','.join(self._device_map.keys()))) + else: + self._change_device(arg) + else: + print('Invalid device name: {0}'.format(arg)) + + def complete_dev(self, text, line, begidx, endidx): + if not text: + completions = list(self._device_map.keys()) + else: + completions = [item for item in list(self._device_map.keys()) if item.startswith(text)] + + return completions + + def do_list(self, arg): + """List available device files""" + if self._current_device is not None: + print('Device files') + print('------------') + for endpoint, permission in self._ep.items(): + if permission in ('r', 'rw'): + print(" {0:-<2}- {1}".format(permission, endpoint)) + else: + print(" {0:->2}- {1}".format(permission, endpoint)) + + print() + print('Event files') + print('-----------') + for event_id, event_value in sorted(self._device_map[self._current_device].events.items(), key=lambda x: x[0]): + print(" {0: >2} {1}".format(event_id, event_value[0])) + else: + print('Devices') + print('-------') + for device in list(self._device_map.keys()): + print(' {0}'.format(device)) + + def do_ls(self, arg): + """List available device files""" + self.do_list(arg) + + def do_read(self, arg, binary=False): + """Read ASCII from given device file""" + if self._current_device is not None: + if arg in self._ep: + result = self._device_map[self._current_device].get(arg, binary=binary) + + print(result) + elif arg in self._ep: + print('Device endpoint not readable') + else: + print("Device endpoint not found") + + def do_binary_read(self, arg): + """Read binary from given device file""" + self.do_read(arg, binary=True) + + def complete_read(self, text, line, begidx, endidx): + if not text: + completions = self._read + else: + completions = [item for item in self._read if item.startswith(text)] + + return completions + + complete_binary_read = complete_read + + def do_write(self, arg): + """Write ASCII to device file. DEVICE_FILE DATA""" + if self._current_device is not None: + try: + device_file, data = arg.split(' ', 1) + + if device_file in self._ep: + if len(data) > 0: + self._device_map[self._current_device].set(device_file, data) + + print("{0}: {1}".format(device_file, self._device_map[self._current_device].get(device_file))) + else: + print("Device endpoint not found") + + except ValueError: + print("Must specify a device endpoint then a space then data to write") + + def complete_write(self, text, line, begidx, endidx): + if not text: + completions = self._write + else: + completions = [item for item in self._write if item.startswith(text)] + + return completions + + def do_event(self, arg): + """Emit an event, format: EVENT_ID KEY_ID STATE + + Where state in 'up' 'down' and 'repeat' + """ + if self._current_device is not None: + try: + event_file, key_id, value = arg.split(' ') + except ValueError: + print("Usage: event event_file key_id value") + return + + if event_file not in self._device_map[self._current_device].events: + print("Event ID {0} is invalid".format(event_file)) + else: + try: + bytes_written = self._device_map[self._current_device].emit_kb_event(event_file, int(key_id), value) + print("Wrote {0} bytes to {1}".format(bytes_written, self._device_map[self._current_device].events[event_file][0])) + except ValueError as err: + print("Caught exception: {0}".format(err)) + + def do_exit(self, arg): + """Exit""" + if self._current_device is not None: + self._change_device(None) + return False + else: + return True + + def do_EOF(self, arg): + """Press Ctrl+D to exit""" + self.do_exit(arg) + + +def create_envionment(device_name, destination): + os.makedirs(destination, exist_ok=True) + + try: + fake_device = fake_driver.FakeDevice(device_name, tmp_dir=destination) + return fake_device + except ValueError: + print('Device {0}.cfg not found'.format(device_name)) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('device', metavar='DEVICE', nargs='*', help='Device config name') + parser.add_argument('--dest', metavar='DESTDIR', required=False, default=None, help='Directory to create driver files in. If omitted then a tmp directory is used') + parser.add_argument('--all', action='store_true', help='Create all possible fake devices') + parser.add_argument('--non-interactive', dest='interactive', action='store_false', help='Dont display prompt, just hang until killed') + parser.add_argument('--clear-dest', action='store_true', help='Clear the destination folder if it exists before starting') + + return parser.parse_args() + + +def run(): + args = parse_args() + + if args.dest is None: + destination = tempfile.mkdtemp(prefix='tmp_', suffix='_fakerazer') + else: + destination = args.dest + + if args.clear_dest and os.path.exists(destination): + shutil.rmtree(destination, ignore_errors=True) + + if args.all: + devices = fake_driver.SPECS + else: + devices = args.device + + device_map = {} + for device in devices: + # Device name: FakeDriver + fake_device = create_envionment(device, destination) + if fake_device is not None: + device_map[device] = fake_device + + if len(device_map) == 0: + print("ERROR: No valid devices passed to script, you either need to pass devices as arguments or use '--all'") + sys.exit(1) + + # Register cleanup + if args.dest is None: + atexit.register(lambda: shutil.rmtree(destination, ignore_errors=True)) + else: + for device in device_map.values(): + # device = FakeDriver + atexit.register(device.close) + + print("Device test directory: {0}".format(destination)) + + try: + if not args.interactive: + print("Sleeping forever, use Ctrl-C to exit...") + while True: + time.sleep(99999999) + else: + FakeDevicePrompt(device_map).cmdloop() + except KeyboardInterrupt: + pass + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/daemon/chroma_keyboard/custom_effect.py b/openrazer/scripts/daemon/chroma_keyboard/custom_effect.py new file mode 100644 index 00000000..484c2d85 --- /dev/null +++ b/openrazer/scripts/daemon/chroma_keyboard/custom_effect.py @@ -0,0 +1,56 @@ +import sys +import time + +import openrazer.client + +device_manager = openrazer.client.DeviceManager() +keyboard = None + +for device in device_manager.devices: + if device.type == 'keyboard': + keyboard = device + break +else: + print("Could not find suitable keyboard", file=sys.stderr) + sys.exit(1) + +if not keyboard.has('lighting_led_matrix'): + print("Keyboard doesn't have LED matrix", file=sys.stderr) + sys.exit(1) + +ROWS = 6 +COLS = 22 +COLOUR = (0, 255, 0) + +keyboard.fx.none() + +last_row = 5 +last_col = 0 + +while last_row >= 0 and last_col >= 0: + for row in range(0, ROWS): + if row % 2 == 0: + col_range = range(0, COLS) + else: + col_range = range(COLS - 1, -1, -1) + + for col in col_range: + if not (row == 0 and col in (18, 19, 20, 21)) and not (row == 5 and col in (4, 5, 6, 8, 9, 10)): # Skip big dead area + keyboard.fx.advanced.matrix.reset() + keyboard.fx.advanced.matrix[row, col] = COLOUR + keyboard.fx.advanced.draw_fb_or() + # keyboard.fx.advanced.draw() + time.sleep(0.05) + + if row == last_row and col == last_col: + if row % 2 == 0: + last_col -= 1 + else: + last_col += 1 + keyboard.fx.advanced.matrix.to_framebuffer_or() + + if row == last_row: + if row % 2 == 0 and last_col == 0: + last_row -= 1 + if row % 2 != 0 and last_col == 21: + last_row -= 1 diff --git a/openrazer/scripts/daemon/chroma_keyboard/game_mode_led.py b/openrazer/scripts/daemon/chroma_keyboard/game_mode_led.py new file mode 100644 index 00000000..0d400c7f --- /dev/null +++ b/openrazer/scripts/daemon/chroma_keyboard/game_mode_led.py @@ -0,0 +1,39 @@ +import sys +import argparse + +import openrazer.client + +choices = ('get', 'on', 'off') +parser = argparse.ArgumentParser() +parser.add_argument('action', choices=choices) +args = parser.parse_args() + +device_manager = openrazer.client.DeviceManager() +keyboard = None + +for device in device_manager.devices: + if device.type == 'keyboard': + keyboard = device + break +else: + print("Could not find suitable keyboard", file=sys.stderr) + sys.exit(1) + + +# Check keyboard has game_mode +if not keyboard.has('game_mode_led'): + print("Keyboard doesn't have game mode", file=sys.stderr) + sys.exit(1) + + +if args.action == 'get': + if keyboard.game_mode_led: + print("Game mode LED: On") + else: + print("Game mode LED: Off") +elif args.action == 'on': + keyboard.game_mode_led = True + print("Turned game mode LED on") +else: + keyboard.game_mode_led = False + print("Turned game mode LED off") diff --git a/openrazer/scripts/daemon/chroma_keyboard/keyboard_info.py b/openrazer/scripts/daemon/chroma_keyboard/keyboard_info.py new file mode 100644 index 00000000..16379965 --- /dev/null +++ b/openrazer/scripts/daemon/chroma_keyboard/keyboard_info.py @@ -0,0 +1,39 @@ +import sys + +import openrazer.client + +device_manager = openrazer.client.DeviceManager() +keyboard = None + + +def on_off(value, true='On', false='Off'): + if value: + return true + else: + return false + + +for device in device_manager.devices: + if device.type == 'keyboard': + keyboard = device + break +else: + print("Could not find suitable keyboard", file=sys.stderr) + sys.exit(1) + +print("Name: {0}".format(keyboard.name)) +print("Type: {0}".format(keyboard.type)) +print("Serial: {0}".format(keyboard.serial)) +print("Firmware Version: {0}".format(keyboard.firmware_version)) +print("------------------------") +print("Brightness: {0}".format(keyboard.brightness)) +if keyboard.has("game_mode_led"): + print("Game Mode LED: {0}".format(on_off(keyboard.game_mode_led))) +if keyboard.has("macro_mode_led"): + macro_led = on_off(keyboard.macro_mode_led) + macro_led_state = on_off(keyboard.macro_mode_led_effect == openrazer.client.constants.MACRO_LED_STATIC, true='Static', false='Blinking') + print("Macro Mode LED: {0} ({1})".format(macro_led, macro_led_state)) +print("------------------------") +print("Capabilities:") +for key, value in sorted(keyboard.capabilities.items(), key=lambda x: x[0]): + print(" {0}: {1}".format(key, value)) diff --git a/openrazer/scripts/daemon/chroma_keyboard/macro_mode_led.py b/openrazer/scripts/daemon/chroma_keyboard/macro_mode_led.py new file mode 100644 index 00000000..36fba7a8 --- /dev/null +++ b/openrazer/scripts/daemon/chroma_keyboard/macro_mode_led.py @@ -0,0 +1,57 @@ +import sys +import argparse + +import openrazer.client + +choices = ('get', 'on', 'off', 'flashing', 'static', 'effect_state') +parser = argparse.ArgumentParser() +parser.add_argument('action', choices=choices) +args = parser.parse_args() + +device_manager = openrazer.client.DeviceManager() +keyboard = None + +for device in device_manager.devices: + if device.type == 'keyboard': + keyboard = device + break +else: + print("Could not find suitable keyboard", file=sys.stderr) + sys.exit(1) + + +# Check keyboard has macro_mode +if not keyboard.has('macro_mode_led'): + print("Keyboard doesn't have macro mode", file=sys.stderr) + sys.exit(1) + + +if args.action == 'get': + if keyboard.macro_mode_led: + print("Macro mode LED: On") + else: + print("Macro mode LED: Off") + +elif args.action == 'effect_state': + if keyboard.macro_mode_led_effect == openrazer.client.constants.MACRO_LED_BLINK: + print("Macro mode LED: Blinking") + else: + print("Macro mode LED: Static") + +elif args.action == 'on': + keyboard.macro_mode_led = True + print("Turned macro mode LED on") + +elif args.action == 'flashing': + keyboard.macro_mode_led = True + keyboard.macro_mode_led_effect = openrazer.client.constants.MACRO_LED_BLINK + print("Turned macro mode LED on (flashing)") + +elif args.action == 'static': + keyboard.macro_mode_led = True + keyboard.macro_mode_led_effect = openrazer.client.constants.MACRO_LED_STATIC + print("Turned macro mode LED on (static)") + +else: # Off + keyboard.macro_mode_led = False + print("Turned macro mode LED off") diff --git a/openrazer/scripts/daemon/chroma_keyboard/standard_effects.py b/openrazer/scripts/daemon/chroma_keyboard/standard_effects.py new file mode 100644 index 00000000..671a5f57 --- /dev/null +++ b/openrazer/scripts/daemon/chroma_keyboard/standard_effects.py @@ -0,0 +1,162 @@ +import sys +import argparse + +import openrazer.client +import openrazer.client.constants as c + + +def ripple_single_type() -> callable: + """ + Creates a simple callable which will convert int, int, int, float + :return: Function + :rtype: callable + """ + count = 0 + + def parse(arg_value): + nonlocal count + + if count < 3: + count += 1 + try: + return int(arg_value) + except ValueError: + raise argparse.ArgumentTypeError("{0} is not an integer".format(arg_value)) + try: + return float(arg_value) + except ValueError: + raise argparse.ArgumentTypeError("{0} is not a float".format(arg_value)) + return parse + + +parser = argparse.ArgumentParser() +action = parser.add_mutually_exclusive_group(required=True) +action.add_argument('--breath-random', action='store_true') +action.add_argument('--breath-single', nargs=3, metavar=('R', 'G', 'B'), type=int) +action.add_argument('--breath-dual', nargs=6, metavar=('R1', 'G1', 'B1', 'R2', 'G2', 'B2'), type=int) +action.add_argument('--reactive', nargs=4, metavar=('TIME', 'R', 'G', 'B'), type=int) +action.add_argument('--spectrum', action='store_true') +action.add_argument('--static', nargs=3, metavar=('R', 'G', 'B'), type=int) +action.add_argument('--wave', metavar='DIRECTION', choices=('LEFT', 'RIGHT'), type=str) +action.add_argument('--ripple-single', nargs=4, metavar='R G B REFRESH_RATE', type=ripple_single_type()) +action.add_argument('--ripple-random', metavar='REFRESH_RATE', type=float) + +args = parser.parse_args() + +device_manager = openrazer.client.DeviceManager() +keyboard = None + +for device in device_manager.devices: + if device.type == 'keyboard': + keyboard = device + break +else: + print("Could not find suitable keyboard", file=sys.stderr) + sys.exit(1) + +if args.breath_random: + if keyboard.fx.has("breath_random"): + keyboard.fx.breath_random() + else: + print("Keyboard doesn't support random breath mode", file=sys.stderr) + sys.exit(1) + +elif args.breath_single is not None: + r, g, b = args.breath_single + assert 0 <= r <= 255, "Red component must be between 0-255 inclusive" + assert 0 <= g <= 255, "Green component must be between 0-255 inclusive" + assert 0 <= b <= 255, "Blue component must be between 0-255 inclusive" + + if keyboard.fx.has("breath_single"): + keyboard.fx.breath_single(r, g, b) + else: + print("Keyboard doesn't support single breath mode", file=sys.stderr) + sys.exit(1) + +elif args.breath_dual is not None: + r1, g1, b1, r2, g2, b2 = args.breath_dual + assert 0 <= r1 <= 255, "Red component must be between 0-255 inclusive" + assert 0 <= g1 <= 255, "Green component must be between 0-255 inclusive" + assert 0 <= b1 <= 255, "Blue component must be between 0-255 inclusive" + assert 0 <= r2 <= 255, "Red component must be between 0-255 inclusive" + assert 0 <= g2 <= 255, "Green component must be between 0-255 inclusive" + assert 0 <= b2 <= 255, "Blue component must be between 0-255 inclusive" + + if keyboard.fx.has("breath_dual"): + keyboard.fx.breath_dual(r1, g1, b1, r2, g2, b2) + else: + print("Keyboard doesn't support dual breath mode", file=sys.stderr) + sys.exit(1) + +elif args.reactive is not None: + t, r, g, b = args.reactive + assert t in (c.REACTIVE_500MS, c.REACTIVE_1000MS, c.REACTIVE_1500MS, c.REACTIVE_2000MS) + assert 0 <= r <= 255, "Red component must be between 0-255 inclusive" + assert 0 <= g <= 255, "Green component must be between 0-255 inclusive" + assert 0 <= b <= 255, "Blue component must be between 0-255 inclusive" + + if keyboard.fx.has("reactive"): + keyboard.fx.reactive(t, r, g, b) + else: + print("Keyboard doesn't support reactive mode", file=sys.stderr) + sys.exit(1) + +elif args.spectrum: + if keyboard.fx.has("spectrum"): + keyboard.fx.spectrum() + else: + print("Keyboard doesn't support spectrum mode", file=sys.stderr) + sys.exit(1) + +elif args.static is not None: + r, g, b = args.static + assert 0 <= r <= 255, "Red component must be between 0-255 inclusive" + assert 0 <= g <= 255, "Green component must be between 0-255 inclusive" + assert 0 <= b <= 255, "Blue component must be between 0-255 inclusive" + + if keyboard.fx.has("static"): + keyboard.fx.static(r, g, b) + else: + print("Keyboard doesn't support static mode", file=sys.stderr) + sys.exit(1) + +elif args.wave is not None: + direction = args.wave + if direction == 'LEFT': + direction = c.WAVE_LEFT + else: + direction = c.WAVE_RIGHT + + if keyboard.fx.has("wave"): + keyboard.fx.wave(direction) + else: + print("Keyboard doesn't support wave mode", file=sys.stderr) + sys.exit(1) + +elif args.ripple_single: + r, g, b, refresh_rate = args.ripple_single + assert 0 <= r <= 255, "Red component must be between 0-255 inclusive" + assert 0 <= g <= 255, "Green component must be between 0-255 inclusive" + assert 0 <= b <= 255, "Blue component must be between 0-255 inclusive" + assert refresh_rate > 0, "Refresh rate cannot be negative" + + if keyboard.fx.has("ripple"): + keyboard.fx.ripple(r, g, b, refresh_rate) + else: + print("Keyboard doesn't support static mode", file=sys.stderr) + sys.exit(1) + +elif args.ripple_random: + refresh_rate = args.ripple_random + assert refresh_rate > 0, "Refresh rate cannot be negative" + + if keyboard.fx.has("ripple"): + keyboard.fx.ripple_random(refresh_rate) + else: + print("Keyboard doesn't support static mode", file=sys.stderr) + sys.exit(1) + +else: + # Logically impossible to reach here + print("Unknown option", file=sys.stderr) + sys.exit(1) diff --git a/openrazer/scripts/daemon/controller.py b/openrazer/scripts/daemon/controller.py new file mode 100644 index 00000000..6990fdf0 --- /dev/null +++ b/openrazer/scripts/daemon/controller.py @@ -0,0 +1,255 @@ +#!/usr/bin/python3 +import argparse +import openrazer.client + +import sys + + +def _clamp_u8(value): + if value > 255: + return 255 + elif value < 0: + return 0 + else: + return value + + +def _print_table(header_list, rows): + column_lengths = [len(header_item) for header_item in header_list] + + for row in rows: + for index, column in enumerate(row): + column = str(column) + + cell_length = len(column) + + try: + if column_lengths[index] < cell_length: + column_lengths[index] = cell_length + except IndexError: + pass + + # spaces in between columns + total column length + max_line_length = ((len(column_lengths) - 1) * 4) + sum(column_lengths) + + # Got maximum column widths + + result = '' + for index, header_item in enumerate(header_list): + pad = ' ' * (column_lengths[index] - len(header_item)) + + result += '{0}{1} '.format(header_item, pad) + + # Remove trailing space, add newline + result += (' ' * (max_line_length - len(result))) + '\n' + # Add ----- separator and newline + result += ('-' * max_line_length) + '\n' + + for row in rows: + line = '' + for index, column in enumerate(row): + column = str(column) + + pad = ' ' * (column_lengths[index] - len(column)) + + line += '{0}{1} '.format(column, pad) + line += (' ' * (max_line_length - len(line))) + '\n' + result += line + + print(result) + + +def _get_devices() -> list: + """ + Gets devices ordered by serial + + :return: List of devices ordered by serial + :rtype: list + """ + device_manager = openrazer.client.DeviceManager() + + devices = sorted(device_manager.devices, key=lambda x: (str(x.serial), str(x.type))) + + return devices + + +def _get_devices_by_serial() -> dict: + device_manager = openrazer.client.DeviceManager() + + devices = {device.serial: device for device in device_manager.devices} + + return devices + + +def _get_devices_by_type() -> dict: + device_manager = openrazer.client.DeviceManager() + + devices = {} + + for device in device_manager.devices: + dev_type = device.type + + try: + devices[dev_type].append(device) + except KeyError: + devices[dev_type] = [device] + + # Sort devices + for key in devices.copy(): + devices[key] = sorted(devices[key], key=lambda x: str(x.serial)) + + return devices + + +def _get_device_from_filter(args): + if args.serial is not None: + device = _get_devices_by_serial().get(args.serial, None) + elif '--keyboard' in sys.argv: + if args.keyboard is None: + args.keyboard = 0 + try: + device = _get_devices_by_type().get('keyboard', [])[args.keyboard] + except IndexError: + device = None + elif '--mouse' in sys.argv: + if args.mouse is None: + args.mouse = 0 + try: + device = _get_devices_by_type().get('mouse', [])[args.mouse] + except IndexError: + device = None + elif '--firefly' in sys.argv: + if args.firefly is None: + args.firefly = 0 + try: + device = _get_devices_by_type().get('firefly', [])[args.firefly] + except IndexError: + device = None + elif '--tartarus' in sys.argv: + if args.tartarus is None: + args.tartarus = 0 + try: + device = _get_devices_by_type().get('tartarus', [])[args.tartarus] + except IndexError: + device = None + else: + # Theoretically impossible to land here + device = None + + if device is None: + print("Could not find device") + sys.exit(1) + else: + return device + + +def list_devices(args): + """ + Subcommand to list all devices + + :param args: Argparse arguments + """ + devices = _get_devices() + + headers = ['ID', 'Device Name', 'Device Type', 'Serial'] + + rows = [] + for index, device in enumerate(devices): + rows.append([ + index, + device.name, + device.type.title(), + device.serial + ]) + + _print_table(headers, rows) + + +def brightness_func(args): + device = _get_device_from_filter(args) + + if args.set is None: + # Get brightness + if args.raw: + print(str(device.brightness)) + else: + print("Brightness: {0}%".format(device.brightness)) + else: + brightness_value = float(_clamp_u8(args.set)) + + if not args.raw: + print("Setting brightness to {0}%".format(brightness_value)) + + device.brightness = brightness_value + + +def parse_args(): + def add_filter_group(sub): + group = sub.add_mutually_exclusive_group(required=True) + group.add_argument('--serial', help='Select device via its serial') + group.add_argument('--keyboard', nargs='?', default=0, type=int, help='Select keyboard, if ID is omitted the first is used') + group.add_argument('--mouse', nargs='?', default=0, type=int, help='Select mouse, if ID is omitted the first is used') + group.add_argument('--firefly', nargs='?', default=0, type=int, help='Select Firefly, if ID is omitted the first is used') + group.add_argument('--tartarus', nargs='?', default=0, type=int, help='Select Tartarus, if ID is omitted the first is used') + + def add_raw(sub): + sub.add_argument('--raw', action='store_true', help="Raw output") + + parser = argparse.ArgumentParser() + subparser = parser.add_subparsers(dest='command', help='commands') + subparser.required = True + + help_parser = subparser.add_parser('help', help='The help command will display help, running "help " will display more detailed help') + help_parser.add_argument('help', nargs='?', metavar='COMMAND', default=None, type=str) + + # No need to assign to a var as it has no args + subparser.add_parser('list', help='Lists Razer Devices') + + # Brightness + brightness_parser = subparser.add_parser('brightness', help='Get or set the brightness') + add_filter_group(brightness_parser) + add_raw(brightness_parser) + brightness_parser.add_argument('--set', metavar='BRIGHTNESS', type=float, default=None, help='Gets brightness if omitted') + + # Macro + macro_parser = subparser.add_parser('macro', help='Manage macros') + add_filter_group(macro_parser) + macro_exclusive_group = macro_parser.add_mutually_exclusive_group(required=True) + macro_exclusive_group.add_argument('--list', action='store_true', help="List active macros") + macro_exclusive_group.add_argument('--add-script', nargs=2, type=str, metavar=('BIND_KEY', 'SCRIPT_PATH'), help="Bind the given script to the given macro key. If you require script arguments either create a wrapper or use the API direct.") + macro_exclusive_group.add_argument('--add-url', nargs=2, type=str, metavar=('BIND_KEY', 'URL'), help="Bind the given URL to the given macro key, so that xdg-open will open a tab.") + macro_exclusive_group.add_argument('--add-keys', nargs='+', type=str, metavar=('BIND_KEY', 'KEYS'), help="Bind the given key string to the given macro key.") + + args = parser.parse_args() + + if args.command == 'help': + if args.help == 'brightness': + brightness_parser.print_help() + elif args.help == 'macro': + macro_parser.print_help() + else: + parser.print_help() + sys.exit(0) + + return args + + +CMD_MAP = { + 'list': list_devices, + 'brightness': brightness_func +} + + +def run(): + args = parse_args() + + if args.command in CMD_MAP: + CMD_MAP[args.command](args) + else: + print('Someone forgot to add mapping for command "{0}"'.format(args.command)) + + print() + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/driver/blackwidow_chroma_keyboard/test.py b/openrazer/scripts/driver/blackwidow_chroma_keyboard/test.py new file mode 100755 index 00000000..79d53687 --- /dev/null +++ b/openrazer/scripts/driver/blackwidow_chroma_keyboard/test.py @@ -0,0 +1,171 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join('/sys/bus/hid/drivers/razerkbd', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-game-led', action='store_true') + parser.add_argument('--skip-macro-led', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x0203), start=1): + found_chroma = True + + print("Blackwidow Chroma {0}\n".format(index)) + + print("Driver version: {0}".format(read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format(read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format(read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format(read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format(read_string(driver_path, 'device_mode'))) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Wave Left") + write_string(driver_path, 'matrix_effect_wave', '1') + time.sleep(5) + print("Wave Right") + write_string(driver_path, 'matrix_effect_wave', '2') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # Custom LEDs all rows + payload_all = b'' + for row in range(0, 6): # 0x15 is 21. 0->21 inclusive + payload_all += row.to_bytes(1, byteorder='big') + b'\x00\x15' + for i in range(0, 22): + payload_all += random.choice(COLOURS) + # Custom LEDs M1-5 + payload_m1_5 = b'' + for row in range(0, 6): # Column 0 or column 0 + payload_m1_5 += row.to_bytes(1, byteorder='big') + b'\x00\x00' + b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test. Setting M1-5 to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_m1_5) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + if not args.skip_game_led: + # Game mode test + print("Starting game mode LED tests. Press enter to begin.") + input() + print("Enabling game mode LED") + write_string(driver_path, 'game_led_state', '1') + time.sleep(5) + print("Disabling game mode LED") + write_string(driver_path, 'game_led_state', '0') + time.sleep(5) + + if not args.skip_macro_led: + print("Starting marco LED tests. Press enter to begin.") + input() + print("Enabling macro mode LED") + write_string(driver_path, 'macro_led_state', '1') + time.sleep(5) + print("Enabling macro mode LED static effect") + write_string(driver_path, 'macro_led_effect', '0') + time.sleep(5) + print("Enabling macro mode LED blinking effect") + write_string(driver_path, 'macro_led_effect', '1') + time.sleep(5) + + write_string(driver_path, 'macro_led_effect', '0') + + print("Disabling macro mode LED") + write_string(driver_path, 'macro_led_state', '0') + time.sleep(5) + + print("Finished") + + if not found_chroma: + print("No Blackwidow Chromas found") diff --git a/openrazer/scripts/driver/blackwidow_elite/test.py b/openrazer/scripts/driver/blackwidow_elite/test.py new file mode 100755 index 00000000..7c71a074 --- /dev/null +++ b/openrazer/scripts/driver/blackwidow_elite/test.py @@ -0,0 +1,190 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join('/sys/bus/hid/drivers/razerkbd', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-game-led', action='store_true') + parser.add_argument('--skip-macro-led', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x0228), start=1): + found_chroma = True + + print("BlackWidow Elite {0}\n".format(index)) + + print("Driver version: {0}".format(read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format(read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format(read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format(read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format(read_string(driver_path, 'device_mode'))) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Wave Left") + write_string(driver_path, 'matrix_effect_wave', '0') + time.sleep(5) + print("Wave Right") + write_string(driver_path, 'matrix_effect_wave', '1') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + print("Starlight random fast") + write_binary(driver_path, 'matrix_effect_starlight', b'\x01') + time.sleep(5) + print("Starlight random slow") + write_binary(driver_path, 'matrix_effect_starlight', b'\x03') + time.sleep(10) + + print("Starlight red fast") + write_binary(driver_path, 'matrix_effect_starlight', b'\x01\xFF\x00\x00') + time.sleep(10) + print("Starlight blue-green fast") + write_binary(driver_path, 'matrix_effect_starlight', b'\x01\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # Custom LEDs all rows + payload_all = b'' + for row in range(0, 6): # 0x15 is 21. 0->21 inclusive + payload_all += row.to_bytes(1, byteorder='big') + b'\x00\x15' + for i in range(0, 22): + payload_all += random.choice(COLOURS) + # Custom LEDs M1-5 + payload_m1_5 = b'' + for row in range(0, 6): # Column 0 or column 0 + payload_m1_5 += row.to_bytes(1, byteorder='big') + b'\x01\x01' + b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test. Setting left hand keys to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_m1_5) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + if not args.skip_game_led: + # Game mode test + print("Starting game mode LED tests. Press enter to begin.") + input() + print("Enabling game mode LED") + write_string(driver_path, 'game_led_state', '1') + time.sleep(5) + print("Disabling game mode LED") + write_string(driver_path, 'game_led_state', '0') + time.sleep(5) + + if not args.skip_macro_led: + print("Putting keyboard into driver mode as that is required for macro LED. Device mode: ", end='') + write_binary(driver_path, 'device_mode', b'\x03\x00') + time.sleep(5) + print(read_string(driver_path, 'device_mode')) + time.sleep(1) + + print("Starting marco LED tests. Press enter to begin.") + input() + print("Enabling macro mode LED") + write_string(driver_path, 'macro_led_state', '1') + time.sleep(5) + print("Enabling macro mode LED static effect") + write_string(driver_path, 'macro_led_effect', '0') + time.sleep(5) + print("Enabling macro mode LED blinking effect") + write_string(driver_path, 'macro_led_effect', '1') + time.sleep(5) + + write_string(driver_path, 'macro_led_effect', '0') + + print("Disabling macro mode LED") + write_string(driver_path, 'macro_led_state', '0') + time.sleep(5) + + print("Finished") + + if not found_chroma: + print("No Blackwidow Chromas found") diff --git a/openrazer/scripts/driver/firefly/test.py b/openrazer/scripts/driver/firefly/test.py new file mode 100755 index 00000000..5590d97e --- /dev/null +++ b/openrazer/scripts/driver/firefly/test.py @@ -0,0 +1,140 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join('/sys/bus/hid/drivers/razeraccessory', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-game-led', action='store_true') + parser.add_argument('--skip-macro-led', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x0C00), start=1): + found_chroma = True + + print("Razer Firefly {0}\n".format(index)) + + print("Driver version: {0}".format(read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format(read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format(read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format(read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format(read_string(driver_path, 'device_mode'))) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Wave Left") + write_string(driver_path, 'matrix_effect_wave', '1') + time.sleep(5) + print("Wave Right") + write_string(driver_path, 'matrix_effect_wave', '2') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # Custom LEDs all rows + payload_all = b'\x00\x00\x0E' + for i in range(0, 15): # 15 colours 0x00-0x0E + payload_all += random.choice(COLOURS) + + payload_m1_5 = b'' + for led in (0x00, 0x0E): + led_byte = led.to_bytes(1, byteorder='big') + payload_m1_5 += b'\x00' + led_byte + led_byte + b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test. First and last led to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_m1_5) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + print("Finished") + + if not found_chroma: + print("No Fireflies found") diff --git a/openrazer/scripts/driver/firefly_hyperflux/test.py b/openrazer/scripts/driver/firefly_hyperflux/test.py new file mode 100644 index 00000000..88bfd2b6 --- /dev/null +++ b/openrazer/scripts/driver/firefly_hyperflux/test.py @@ -0,0 +1,140 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join('/sys/bus/hid/drivers/razeraccessory', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-game-led', action='store_true') + parser.add_argument('--skip-macro-led', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x0068), start=1): + found_chroma = True + + print("Razer Firefly_hyperflux {0}\n".format(index)) + + print("Driver version: {0}".format(read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format(read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format(read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format(read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format(read_string(driver_path, 'device_mode'))) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Wave Left") + write_string(driver_path, 'matrix_effect_wave', '1') + time.sleep(5) + print("Wave Right") + write_string(driver_path, 'matrix_effect_wave', '2') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # Custom LEDs all rows + payload_all = b'\x00\x00\x0E' + for i in range(0, 15): # 15 colours 0x00-0x0E + payload_all += random.choice(COLOURS) + + payload_m1_5 = b'' + for led in (0x00, 0x0E): + led_byte = led.to_bytes(1, byteorder='big') + payload_m1_5 += b'\x00' + led_byte + led_byte + b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test. First and last led to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_m1_5) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + print("Finished") + + if not found_chroma: + print("No Fireflies found") diff --git a/openrazer/scripts/driver/firefly_v2/test.py b/openrazer/scripts/driver/firefly_v2/test.py new file mode 100644 index 00000000..0d9caf75 --- /dev/null +++ b/openrazer/scripts/driver/firefly_v2/test.py @@ -0,0 +1,140 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join('/sys/bus/hid/drivers/razeraccessory', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-game-led', action='store_true') + parser.add_argument('--skip-macro-led', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x0C04), start=1): + found_chroma = True + + print("Razer Firefly_hyperflux {0}\n".format(index)) + + print("Driver version: {0}".format(read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format(read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format(read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format(read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format(read_string(driver_path, 'device_mode'))) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Wave Left") + write_string(driver_path, 'matrix_effect_wave', '1') + time.sleep(5) + print("Wave Right") + write_string(driver_path, 'matrix_effect_wave', '2') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # Custom LEDs all rows + payload_all = b'\x00\x00\x12' + for i in range(0, 19): # 19 colours 0x00-0x12 + payload_all += random.choice(COLOURS) + + payload_m1_5 = b'' + for led in (0x00, 0x12): + led_byte = led.to_bytes(1, byteorder='big') + payload_m1_5 += b'\x00' + led_byte + led_byte + b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test. First and last led to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_m1_5) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + print("Finished") + + if not found_chroma: + print("No Fireflies V2 found") diff --git a/openrazer/scripts/driver/goliathus/test.py b/openrazer/scripts/driver/goliathus/test.py new file mode 100755 index 00000000..4fd25257 --- /dev/null +++ b/openrazer/scripts/driver/goliathus/test.py @@ -0,0 +1,165 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', + b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join( + '/sys/bus/hid/drivers/razeraccessory', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-game-led', action='store_true') + parser.add_argument('--skip-macro-led', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x0C02), start=1): + found_chroma = True + + print("Razer Goliathus {0}\n".format(index)) + + print("Driver version: {0}".format( + read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format( + read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format( + read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format( + read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format( + read_string(driver_path, 'device_mode'))) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format( + read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format( + read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format( + read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting reactive tests. Press enter to begin.") + input() + print("Reactive blue") + write_binary(driver_path, 'matrix_effect_reactive', b'\x01\x00\x00\xFF') + time.sleep(2) + print("Trigger reactive") + write_string(driver_path, 'matrix_reactive_trigger', '1') + time.sleep(2) + print("Trigger reactive") + write_string(driver_path, 'matrix_reactive_trigger', '1') + time.sleep(2) + print("Trigger reactive") + write_string(driver_path, 'matrix_reactive_trigger', '1') + time.sleep(2) + print("Trigger reactive") + write_string(driver_path, 'matrix_reactive_trigger', '1') + time.sleep(2) + print("Trigger reactive") + write_string(driver_path, 'matrix_reactive_trigger', '1') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', + b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # row, start_col, end_col + payload_all = b'\x00\x00\x00' + # add 1 column (end_col + 1 - start_col == 0) of LEDs (1 LED) + payload_all += random.choice(COLOURS) + + payload_white = b'\x00\x00\x00' + payload_white += b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test") + print("Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test") + print("Set LED to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_white) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + print("Finished") + + if not found_chroma: + print("No Goliathus found") diff --git a/openrazer/scripts/driver/keyboard_keys.py b/openrazer/scripts/driver/keyboard_keys.py new file mode 100755 index 00000000..5c3cd176 --- /dev/null +++ b/openrazer/scripts/driver/keyboard_keys.py @@ -0,0 +1,56 @@ +#!/usr/bin/python3 +""" +Simple program to walk through each key, illuminating it red so I can see +what element in the 22 RGB list each key refers to. +""" + +import glob + +colour_file = glob.glob('/sys/bus/hid/drivers/razerkbd/0*/matrix_custom_frame')[0] +custom_mode = glob.glob('/sys/bus/hid/drivers/razerkbd/0*/matrix_effect_custom')[0] + + +def clear_row(row_num): + + result = bytes([row_num, 0x00, 0x15]) # Results in b'\x00', b'\x01' ... + + for i in range(0, 22): + result += b'\x00\x00\x00' + + return result + + +def gen_row(row_num): + + result = bytes([row_num, 0, 0x15]) # Results in b'\x00', b'\x01' ... + + for i in range(0, 22): + for j in range(0, 22): + if j == i: + result += b'\x00\xFF\x00' + else: + result += b'\x00\x00\x00' + yield result + + # Reset result + result = bytes([row_num, 0x00, 0x15]) + + +def write_binarystr(filename, binary_str): + with open(filename, 'wb') as bin_file: + bin_file.write(binary_str) + + +for i in range(0, 6): + write_binarystr(colour_file, clear_row(i)) + write_binarystr(custom_mode, bytes('1', 'ascii')) + +for i in range(0, 6): + + for key_id, byte_str in enumerate(gen_row(i)): + write_binarystr(colour_file, byte_str) + write_binarystr(custom_mode, bytes('1', 'ascii')) + print("ROW {0}:{1}".format(i, key_id)) + input() + write_binarystr(colour_file, clear_row(i)) + write_binarystr(custom_mode, bytes('1', 'ascii')) diff --git a/openrazer/scripts/driver/mamba_chroma_wireless_mouse/test.py b/openrazer/scripts/driver/mamba_chroma_wireless_mouse/test.py new file mode 100755 index 00000000..de51b57e --- /dev/null +++ b/openrazer/scripts/driver/mamba_chroma_wireless_mouse/test.py @@ -0,0 +1,181 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random +import struct + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-dpi', action='store_true') + parser.add_argument('--skip-charge-effect', action='store_true') + parser.add_argument('--skip-idle-test', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x0045), start=1): + found_chroma = True + + print("Mamba Chroma {0}\n".format(index)) + + print("Driver version: {0}".format(read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format(read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format(read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format(read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format(read_string(driver_path, 'device_mode'))) + print("Battery level: {0:.2f}%".format(float(read_string(driver_path, 'charge_level')) * 100 / 255)) + print("Charging: {0}".format('yes' if read_string(driver_path, 'charge_status') == '1' else 'no')) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Wave Left") + write_string(driver_path, 'matrix_effect_wave', '1') + time.sleep(5) + print("Wave Right") + write_string(driver_path, 'matrix_effect_wave', '2') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # Custom LEDs all rows + payload_all = b'\x00\x00\x0E' + for i in range(0, 15): # 15 colours 0x00-0x0E + payload_all += random.choice(COLOURS) + + # Custom LEDs M1-5 + payload_m1_5 = b'\x00\x0E\x0E' + b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test. Setting scroll wheel to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_m1_5) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + if not args.skip_dpi: + # DPI test + print("Starting DPI test. Press enter to begin.") + input() + print("Setting X:800 Y:800") + write_binary(driver_path, 'dpi', struct.pack(">HH", 800, 800)) + time.sleep(10) + print("Setting X:8000 Y:8000") + write_binary(driver_path, 'dpi', struct.pack(">HH", 8000, 8000)) + time.sleep(10) + print("Setting X:100 Y:2000") + write_binary(driver_path, 'dpi', struct.pack(">HH", 100, 2000)) + time.sleep(10) + + write_binary(driver_path, 'dpi', struct.pack(">H", 800)) + + if not args.skip_charge_effect: + print("Starting charge effect tests. Place the mouse on the dock. Press enter to when ready.") + input() + write_string(driver_path, 'matrix_effect_wave', '1') + + print("Setting charge effect to use current mouse effect") + write_binary(driver_path, 'charge_effect', b'\x00') + time.sleep(10) + print("Setting charge effect to be static red. If you take the mouse off charge it should revert to wave effect") + + write_binary(driver_path, 'charge_colour', b'\xFF\x00\x00') # Also changes dock type + time.sleep(10) + + if not args.skip_idle_test: + print("Starting device idle test. This will take roughly 5 minutes. Best to literally move away from the desk, mouse can be rather sensitive. Press enter to start.") + input() + print("Setting idle timeout to 60 seconds.") + write_string(driver_path, 'device_idle_time', '60') + time.sleep(90) + + print("Mouse") + write_string(driver_path, 'device_idle_time', '300') + + print("Finished") + + if not found_chroma: + print("No Mamaba found") diff --git a/openrazer/scripts/driver/ornata_chroma_keyboard/test.py b/openrazer/scripts/driver/ornata_chroma_keyboard/test.py new file mode 100755 index 00000000..02b50178 --- /dev/null +++ b/openrazer/scripts/driver/ornata_chroma_keyboard/test.py @@ -0,0 +1,190 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random + + +COLOURS = (b'\xFF\x00\x00', b'\x00\xFF\x00', b'\x00\x00\xFF', b'\xFF\xFF\x00', b'\xFF\x00\xFF', b'\x00\xFF\xFF') + + +def write_binary(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'wb') as open_file: + open_file.write(payload) + + +def read_string(driver_path, device_file): + with open(os.path.join(driver_path, device_file), 'r') as open_file: + return open_file.read().rstrip('\n') + + +def write_string(driver_path, device_file, payload): + with open(os.path.join(driver_path, device_file), 'w') as open_file: + open_file.write(payload) + + +def find_devices(vid, pid): + driver_paths = glob.glob(os.path.join('/sys/bus/hid/drivers/razerkbd', '*:{0:04X}:{1:04X}.*'.format(vid, pid))) + + for driver_path in driver_paths: + device_type_path = os.path.join(driver_path, 'device_type') + + if os.path.exists(device_type_path): + yield driver_path + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--skip-standard', action='store_true') + parser.add_argument('--skip-custom', action='store_true') + parser.add_argument('--skip-game-led', action='store_true') + parser.add_argument('--skip-macro-led', action='store_true') + + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_args() + + found_chroma = False + + for index, driver_path in enumerate(find_devices(0x1532, 0x021E), start=1): + found_chroma = True + + print("Ornata Chroma {0}\n".format(index)) + + print("Driver version: {0}".format(read_string(driver_path, 'version'))) + print("Driver firmware version: {0}".format(read_string(driver_path, 'firmware_version'))) + print("Device serial: {0}".format(read_string(driver_path, 'device_serial'))) + print("Device type: {0}".format(read_string(driver_path, 'device_type'))) + print("Device mode: {0}".format(read_string(driver_path, 'device_mode'))) + + # Set to static red so that we have something standard + write_binary(driver_path, 'matrix_effect_static', b'\xFF\x00\x00') + + if not args.skip_standard: + print("Starting brightness test. Press enter to begin.") + input() + print("Max brightness...", end='') + write_string(driver_path, 'matrix_brightness', '255') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Half brightness...", end='') + write_string(driver_path, 'matrix_brightness', '128') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + print("Zero brightness...", end='') + write_string(driver_path, 'matrix_brightness', '0') + time.sleep(1) + print("brightness ({0})".format(read_string(driver_path, 'matrix_brightness'))) + time.sleep(1) + write_string(driver_path, 'matrix_brightness', '255') + + print("Starting other colour effect tests. Press enter to begin.") + input() + print("Green Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\x00') + time.sleep(5) + print("Cyan Static") + write_binary(driver_path, 'matrix_effect_static', b'\x00\xFF\xFF') + time.sleep(5) + print("Spectrum") + write_binary(driver_path, 'matrix_effect_spectrum', b'\x00') + time.sleep(10) + print("None") + write_binary(driver_path, 'matrix_effect_none', b'\x00') + time.sleep(5) + print("Wave Left") + write_string(driver_path, 'matrix_effect_wave', '0') + time.sleep(5) + print("Wave Right") + write_string(driver_path, 'matrix_effect_wave', '1') + time.sleep(5) + print("Breathing random") + write_binary(driver_path, 'matrix_effect_breath', b'\x00') + time.sleep(10) + print("Breathing red") + write_binary(driver_path, 'matrix_effect_breath', b'\xFF\x00\x00') + time.sleep(10) + print("Breathing blue-green") + write_binary(driver_path, 'matrix_effect_breath', b'\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + print("Starlight random fast") + write_binary(driver_path, 'matrix_effect_starlight', b'\x01') + time.sleep(5) + print("Starlight random slow") + write_binary(driver_path, 'matrix_effect_starlight', b'\x03') + time.sleep(10) + + print("Starlight red fast") + write_binary(driver_path, 'matrix_effect_starlight', b'\x01\xFF\x00\x00') + time.sleep(10) + print("Starlight blue-green fast") + write_binary(driver_path, 'matrix_effect_starlight', b'\x01\x00\xFF\x00\x00\x00\xFF') + time.sleep(10) + + if not args.skip_custom: + # Custom LEDs all rows + payload_all = b'' + for row in range(0, 6): # 0x15 is 21. 0->21 inclusive + payload_all += row.to_bytes(1, byteorder='big') + b'\x00\x15' + for i in range(0, 22): + payload_all += random.choice(COLOURS) + # Custom LEDs M1-5 + payload_m1_5 = b'' + for row in range(0, 6): # Column 0 or column 0 + payload_m1_5 += row.to_bytes(1, byteorder='big') + b'\x01\x01' + b'\xFF\xFF\xFF' + + print("Custom LED matrix colours test. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_all) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + print("Custom LED matrix partial colours test. Setting left hand keys to white. Press enter to begin.") + input() + write_binary(driver_path, 'matrix_custom_frame', payload_m1_5) + write_binary(driver_path, 'matrix_effect_custom', b'\x00') + time.sleep(0.5) + + if not args.skip_game_led: + # Game mode test + print("Starting game mode LED tests. Press enter to begin.") + input() + print("Enabling game mode LED") + write_string(driver_path, 'game_led_state', '1') + time.sleep(5) + print("Disabling game mode LED") + write_string(driver_path, 'game_led_state', '0') + time.sleep(5) + + if not args.skip_macro_led: + print("Putting keyboard into driver mode as that is required for macro LED. Device mode: ", end='') + write_binary(driver_path, 'device_mode', b'\x03\x00') + time.sleep(5) + print(read_string(driver_path, 'device_mode')) + time.sleep(1) + + print("Starting marco LED tests. Press enter to begin.") + input() + print("Enabling macro mode LED") + write_string(driver_path, 'macro_led_state', '1') + time.sleep(5) + print("Enabling macro mode LED static effect") + write_string(driver_path, 'macro_led_effect', '0') + time.sleep(5) + print("Enabling macro mode LED blinking effect") + write_string(driver_path, 'macro_led_effect', '1') + time.sleep(5) + + write_string(driver_path, 'macro_led_effect', '0') + + print("Disabling macro mode LED") + write_string(driver_path, 'macro_led_state', '0') + time.sleep(5) + + print("Finished") + + if not found_chroma: + print("No Blackwidow Chromas found") diff --git a/openrazer/scripts/format_source.sh b/openrazer/scripts/format_source.sh new file mode 100755 index 00000000..11597e6f --- /dev/null +++ b/openrazer/scripts/format_source.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -ex + +# C (astyle) +find driver/ -name "*.c" -o -name "*.h" | xargs astyle --style=linux -n + +# Python (autopep8) +autopep8 --recursive --in-place --max-line-length 500 --ignore E402 . diff --git a/openrazer/scripts/generate_all_fake_drivers.sh b/openrazer/scripts/generate_all_fake_drivers.sh new file mode 100755 index 00000000..b6dd1928 --- /dev/null +++ b/openrazer/scripts/generate_all_fake_drivers.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -e + +if [ "$1" = "-f" ]; then + echo "Removing existing fake driver files..." + rm $(dirname "$0")/../pylib/openrazer/_fake_driver/*.cfg +fi + +drivers=$(ls driver/razer*_driver.c | cut -d'/' -f2 | cut -d'_' -f1) + +for driver in $drivers; do + [ "$driver" = "razercore" ] && continue # razercore is currently broken + $(dirname "$0")/generate_fake_driver.sh $driver +done diff --git a/openrazer/scripts/generate_appstream_file.sh b/openrazer/scripts/generate_appstream_file.sh new file mode 100755 index 00000000..c13257a7 --- /dev/null +++ b/openrazer/scripts/generate_appstream_file.sh @@ -0,0 +1,33 @@ +#!/bin/sh -e + +output_appstream_file="install_files/appstream/io.github.openrazer.openrazer.metainfo.xml" + +# First part of AppStream file +echo ' + + io.github.openrazer.openrazer + CC0-1.0 + GPL-2.0+ + OpenRazer + Drivers for Razer peripherals on GNU/Linux + +

+ OpenRazer is a collection of GNU/Linux drivers for the Razer devices. + Supported devices include keyboards, mice, mouse-mats, headsets and + various other devices. OpenRazer provides kernel drivers, DBus services + and python bindings to interact with the DBus interface. +

+
+ https://openrazer.github.io/ + + #openrazer:matrix.org + https://fosstodon.org/@openrazer + + ' > ${output_appstream_file} + +# Autogeneration of supported devices list +grep -rh "USB_PID = " daemon/openrazer_daemon/hardware/ | cut -d '=' -f2 | grep -v None | sort -f | sed -E 's| 0x([0-9A-Fa-f]{4})| usb:v1532p\1d*|g' >> ${output_appstream_file} + +# First last of AppStream file +echo ' +
' >> ${output_appstream_file} diff --git a/openrazer/scripts/generate_fake_driver.sh b/openrazer/scripts/generate_fake_driver.sh new file mode 100755 index 00000000..bc4da134 --- /dev/null +++ b/openrazer/scripts/generate_fake_driver.sh @@ -0,0 +1,257 @@ +#!/bin/bash + +declare -A files_metadata=( + ["backlight_led_brightness"]="rw;0" + ["backlight_led_state"]="rw;0" + ["backlight_matrix_effect_breath"]="w;" + ["backlight_matrix_effect_none"]="w;" + ["backlight_matrix_effect_on"]="w;" + ["backlight_matrix_effect_reactive"]="w;" + ["backlight_matrix_effect_spectrum"]="w;" + ["backlight_matrix_effect_static"]="w;" + ["backlight_matrix_effect_wave"]="w;" + ["charge_colour"]="w;" + ["charge_effect"]="w;" + ["charge_level"]="r;255" + ["charge_low_threshold"]="rw;38" + ["charge_status"]="r;1" + ["charging_led_brightness"]="rw;0" + ["charging_matrix_effect_breath"]="w;" + ["charging_matrix_effect_none"]="w;" + ["charging_matrix_effect_spectrum"]="w;" + ["charging_matrix_effect_static"]="w;" + ["charging_matrix_effect_wave"]="w;" + ["device_idle_time"]="rw;600" + ["device_mode"]="rw;0x0000" + ["device_serial"]="r;XX0000000000" # default value will get overwritten + ["device_type"]="r;%(name)s" + ["dpi"]="rw;800:800" + ["dpi_stages"]="rw;0x010320032005dc05dc" + ["fast_charging_led_brightness"]="rw;0" + ["fast_charging_matrix_effect_breath"]="w;" + ["fast_charging_matrix_effect_none"]="w;" + ["fast_charging_matrix_effect_spectrum"]="w;" + ["fast_charging_matrix_effect_static"]="w;" + ["fast_charging_matrix_effect_wave"]="w;" + ["firmware_version"]="r;v1.0" + ["fully_charged_led_brightness"]="rw;0" + ["fully_charged_matrix_effect_breath"]="w;" + ["fully_charged_matrix_effect_none"]="w;" + ["fully_charged_matrix_effect_spectrum"]="w;" + ["fully_charged_matrix_effect_static"]="w;" + ["fully_charged_matrix_effect_wave"]="w;" + ["game_led_state"]="rw;0" + ["hyperpolling_wireless_dongle_indicator_led_mode"]="w;" + ["hyperpolling_wireless_dongle_pair"]="w;" + ["hyperpolling_wireless_dongle_unpair"]="w;" + ["keyswitch_optimization"]="rw;0" + ["is_mug_present"]="r;0" + ["kbd_layout"]="r;01" + ["key_alt_f4"]="rw;0x00" + ["key_alt_tab"]="rw;0x00" + ["key_super"]="rw;0x00" + ["left_led_brightness"]="rw;0" + ["left_matrix_effect_breath"]="w;" + ["left_matrix_effect_none"]="w;" + ["left_matrix_effect_reactive"]="w;" + ["left_matrix_effect_spectrum"]="w;" + ["left_matrix_effect_static"]="w;" + ["left_matrix_effect_wave"]="w;" + ["logo_led_brightness"]="rw;0" + ["logo_led_effect"]="rw;0" + ["logo_led_state"]="rw;0" + ["logo_matrix_effect_blinking"]="w;" + ["logo_matrix_effect_breath"]="w;" + ["logo_matrix_effect_none"]="w;" + ["logo_matrix_effect_on"]="w;" + ["logo_matrix_effect_reactive"]="w;" + ["logo_matrix_effect_spectrum"]="w;" + ["logo_matrix_effect_static"]="w;" + ["logo_matrix_effect_wave"]="w;" + ["macro_led_effect"]="rw;0" + ["macro_led_state"]="rw;0" + ["matrix_brightness"]="rw;0" + ["matrix_current_effect"]="w;05" + ["matrix_custom_frame"]="w;" + ["matrix_effect_blinking"]="w;" + ["matrix_effect_breath"]="w;" + ["matrix_effect_custom"]="w;" + ["matrix_effect_none"]="w;" + ["matrix_effect_pulsate"]="w;" + ["matrix_effect_reactive"]="w;" + ["matrix_effect_spectrum"]="w;" + ["matrix_effect_starlight"]="w;" + ["matrix_effect_static"]="w;" + ["matrix_effect_wave"]="w;" + ["matrix_effect_wheel"]="w;" + ["matrix_reactive_trigger"]="w;" + ["poll_rate"]="rw;500" + ["profile_led_blue"]="rw;0" + ["profile_led_green"]="rw;0" + ["profile_led_red"]="rw;0" + ["right_led_brightness"]="rw;0" + ["right_matrix_effect_breath"]="w;" + ["right_matrix_effect_none"]="w;" + ["right_matrix_effect_reactive"]="w;" + ["right_matrix_effect_spectrum"]="w;" + ["right_matrix_effect_static"]="w;" + ["right_matrix_effect_wave"]="w;" + ["scroll_led_brightness"]="rw;0" + ["scroll_led_effect"]="rw;0" + ["scroll_led_state"]="rw;0" + ["scroll_matrix_effect_blinking"]="w;" + ["scroll_matrix_effect_breath"]="w;" + ["scroll_matrix_effect_none"]="w;" + ["scroll_matrix_effect_on"]="w;" + ["scroll_matrix_effect_reactive"]="w;" + ["scroll_matrix_effect_spectrum"]="w;" + ["scroll_matrix_effect_static"]="w;" + ["scroll_matrix_effect_wave"]="w;" + ["scroll_mode"]="rw;0" + ["scroll_acceleration"]="rw;0" + ["scroll_smart_reel"]="rw;0" + ["tilt_hwheel"]="rw;0" + ["tilt_repeat"]="rw;0" + ["tilt_repeat_delay"]="rw;0" + ["reset_channels"]="w;1" + ["channel1_size"]="rw;8" + ["channel2_size"]="rw;8" + ["channel3_size"]="rw;8" + ["channel4_size"]="rw;8" + ["channel5_size"]="rw;8" + ["channel6_size"]="rw;8" + ["channel1_led_brightness"]="rw;0" + ["channel2_led_brightness"]="rw;0" + ["channel3_led_brightness"]="rw;0" + ["channel4_led_brightness"]="rw;0" + ["channel5_led_brightness"]="rw;0" + ["channel6_led_brightness"]="rw;0" + ["version"]="r;1.0.0" +) + +# USB PID of devices that use single-byte values for DPI +byte_dpi_devices=( + '0013' # Razer Orochi 2011 + '0020' # Razer Abyssus 1800 + '002E' # Razer Naga 2012 + '0036' # Razer Naga Hex Red + '0037' # Razer DeathAdder 2013 + '0038' # Razer DeathAdder 1800 + '0041' # Razer Naga Hex +) + + +get_attr_from_create_device_file() { + sed -n 's/[[:space:]]\+CREATE_DEVICE_FILE(&hdev->dev, &dev_attr_\([[:lower:][:digit:]_]\+\));.*/\1/p' +} + +driver=$1 + +if [ -z "$driver" ]; then + echo "Usage: $0 razerkbd/razermouse" + exit 1 +fi + +driver_short=$(echo "$driver" | sed 's/razer//g') + +devices=$(git grep -h "#define USB_DEVICE_ID_RAZER_" driver/${driver}_driver.h | cut -d' ' -f2-3) + +# https://askubuntu.com/a/849016 +probe_func=$(sed -n '/^static int razer_'${driver_short}'_probe/,/^}$/p' driver/${driver}_driver.c) +devicetype_func=$(sed -n '/^static ssize_t razer_attr_read_device_type/,/^}$/p' driver/${driver}_driver.c) + +probe_lines=$(echo "$probe_func" | grep 'case \|CREATE_DEVICE_FILE\|break;') +devicetype_lines=$(echo "$devicetype_func" | grep 'case \|device_type = \|break;') + +# https://unix.stackexchange.com/a/11323 +common_attrs_lines=$(echo "$probe_lines" | sed -ne '/CREATE_DEVICE_FILE/,$ p' | sed '/case USB_DEVICE_ID_RAZER_/Q') +common_attrs=$(echo "$common_attrs_lines" | get_attr_from_create_device_file) + +# Iterate through all devices +while IFS= read -r device_raw; do + device=$(echo "$device_raw" | cut -d' ' -f1) + device_pid=$(echo "$device_raw" | cut -d' ' -f2 | sed 's/0x//') + + devicetype_line=$(echo "$devicetype_lines" | sed -n '/case '$device':/,/break;/p' | grep "device_type = ") + device_name=$(echo "$devicetype_line" | sed 's/[[:space:]]\+device_type = "\(.\+\)\\n";.*/\1/' | sed 's/%/%%/g') + + #echo "-----------------------------" >&2 + echo "Generating for $device_name (1532:$device_pid) ..." >&2 + + device_attrs_lines=$(echo "$probe_lines" | sed -n '/case '$device':/,/break;/p') + device_attrs=$(echo "$device_attrs_lines" | get_attr_from_create_device_file) + + all_attrs=$(echo "$device_attrs"; echo "$common_attrs") + all_attrs=$(echo "$all_attrs" | sort) + + if [ -z "$device_attrs_lines" ]; then + echo "Error: couldn't find _probe lines for device $device" + exit 1 + fi + + device_name_simple=$(echo "$device_name" | tr -d ' ' | tr -d '(' | tr -d ')' | sed 's/%%/pct/g' | tr '[:upper:]' '[:lower:]') + filename="./pylib/openrazer/_fake_driver/$device_name_simple.cfg" + + # There are some devices that have multiple PID for the same codename. + # Why exactly I'm not sure, but we need to add a suffix to the fake driver file then. + if [ "$device_pid" = "0506" ] || # Razer Kraken 7.1 + [ "$device_pid" = "028F" ] || # Razer Ornata V3 + [ "$device_pid" = "02A2" ] || # Razer Ornata V3 X + [ "$device_pid" = "00C2" ] || # Razer DeathAdder V3 Pro (Wired) + [ "$device_pid" = "00C3" ]; then # Razer DeathAdder V3 Pro (Wireless) + filename=${filename%.cfg}_2.cfg + fi + + if [ -f "$filename" ]; then + echo "Error: File $filename already exists!" + exit 1 + fi + + cat << EOF > "$filename" +# DO NOT EDIT THIS FILE! +# You can regenerate all fake driver files with ./scripts/generate_all_fake_drivers.sh -f +[device] +dir_name = 0003:1532:$device_pid.0001 +name = $device_name +EOF + # echo "event = TODO" >> "$filename" + echo -n "files = " >> "$filename" + + first_attr=true + # Iterate through the attributes of the device + while IFS= read -r attr; do + # Ignore some attributes that we don't need in the fake driver + # "": sometimes we get empty line in here + # "test": not used by daemon + # "fn_toggle": not used by daemon + [[ "$attr" = "" || "$attr" = "test" || "$attr" = "fn_toggle" ]] && continue + + metadata="${files_metadata[$attr]}" + if [ -z "$metadata" ]; then + echo "Error: Missing metadata for attr: $attr" + exit 1 + fi + + filemode=${metadata%;*} # part before the semicolon + default=${metadata#*;} # part after the semicolon + + # Handle a few special cases + if [[ "$attr" = "dpi" && " ${byte_dpi_devices[@]} " =~ " ${device_pid} " ]]; then + default="30:30" + elif [ "$attr" = "device_serial" ]; then + default="XX000000$device_pid" + fi + + if [ "$first_attr" = false ]; then + # Indentation + echo -n " " >> "$filename" + fi + echo -n "$filemode,$attr" >> "$filename" + if [ ! -z "$default" ]; then + echo -n ",$default" >> "$filename" + fi + echo >> "$filename" + + first_attr=false + done <<< "$all_attrs" +done <<< "$devices" diff --git a/openrazer/scripts/misc/event_reader.py b/openrazer/scripts/misc/event_reader.py new file mode 100644 index 00000000..88785406 --- /dev/null +++ b/openrazer/scripts/misc/event_reader.py @@ -0,0 +1,67 @@ +import os +import sys +import argparse +import struct +from openrazer_daemon.keyboard import EVENT_MAPPING, TARTARUS_EVENT_MAPPING + +EVENT_FORMAT = '@llHHI' +EVENT_SIZE = struct.calcsize(EVENT_FORMAT) + + +def loop_on_event(event_file, mapping): + with open(event_file, 'rb') as open_file: + + while True: + payload = open_file.read(EVENT_SIZE) + + ev_type, code, value = struct.unpack(EVENT_FORMAT, payload)[2:] + + if (ev_type == code == 0) or ev_type == 4: + continue + + if ev_type == 1: + if value == 0: + value = 'UP' + elif value == 1: + value = 'DOWN' + else: + value = 'REPEAT' + + code = mapping.get(code, code) + + print("Type: EV_KEY, Code: {0}, Value: {1}".format(code, value)) + else: + print("Type: {0}, Code: {1}, Value: {2}".format(ev_type, code, value)) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('event_file', metavar='EVENT_FILE', type=str, help="Device event file like \"/dev/input/by-id/usb-Razer_Razer_BlackWidow_Chroma-event-kbd\"") + parser.add_argument('--tartarus', action='store_true', help='Use the tartarus event mapping instead') + + return parser.parse_args() + + +def run(): + args = parse_args() + + if not os.path.exists(args.event_file): + print('Event file does not exist', file=sys.stderr) + sys.exit(1) + + if args.tartarus: + mapping = TARTARUS_EVENT_MAPPING + else: + # mapping = EVENT_MAPPING + mapping = {} + + print('Starting. Press keys', file=sys.stderr) + + try: + loop_on_event(args.event_file, mapping) + except KeyboardInterrupt: + print("Exiting", file=sys.stderr) + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/breathing_effect.py b/openrazer/scripts/razer_mouse/driver/breathing_effect.py new file mode 100644 index 00000000..e6ae6c00 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/breathing_effect.py @@ -0,0 +1,70 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_u8(value): + if value > 255: + value = 255 + elif value < 0: + value = 0 + return value + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the breathing effect") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--random', action="store_true", help="Random breathing effect") + group.add_argument('--single', nargs=3, metavar=("R", "G", "B"), type=int, help="Single colour breathing effect") + group.add_argument('--dual', nargs=6, metavar=("R1", "G1", "B1", "R2", "G2", "B2"), type=int, help="Dual colour breathing effect") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + if args.random: + byte_string = struct.pack(">B", 0x01) + elif args.single is not None: + values = map(clamp_to_u8, args.single) + byte_string = struct.pack(">BBB", *values) + elif args.dual is not None: + values = map(clamp_to_u8, args.dual) + byte_string = struct.pack(">BBBBBB", *values) + else: + # Should never get here + byte_string = struct.pack(">B", 0x01) + + breathing_mode_filepath = os.path.join(mouse_dir, "mode_breath") + with open(breathing_mode_filepath, 'wb') as breathing_mode_file: + breathing_mode_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/custom_effect.py b/openrazer/scripts/razer_mouse/driver/custom_effect.py new file mode 100644 index 00000000..291a7f00 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/custom_effect.py @@ -0,0 +1,71 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import time +import random +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set a custom colour effect") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + # choices = [b'\xff\x00\x00', b'\xff\xff\x00', b'\x00\xff\x00', b'\x00\xff\xff', b'\x00\x00\xff', b'\xff\x00\xff'] + choices = [b'\xff\x00\x00'] + + for repeat in range(0, 10): + payload = b'' + for i in range(0, 15): + payload += random.choice(choices) + + set_colour_filename = os.path.join(mouse_dir, "set_key_row") + set_custom_mode_filename = os.path.join(mouse_dir, "mode_custom") + with open(set_colour_filename, 'wb') as set_colour_file: + set_colour_file.write(payload) + with open(set_custom_mode_filename, 'w') as set_custom_mode_file: + set_custom_mode_file.write("1") + time.sleep(0.2) + + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/get_battery.py b/openrazer/scripts/razer_mouse/driver/get_battery.py new file mode 100644 index 00000000..8f0deec7 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/get_battery.py @@ -0,0 +1,52 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import sys + + +def parse_args(): + parser = argparse.ArgumentParser(description="Get battery level") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + battery_filepath = os.path.join(mouse_dir, "get_battery") + with open(battery_filepath, 'r') as battery_file: + # Battery percentage, before being scaled to 0-100 + try: + battery_percentage_ns = int(battery_file.read().strip()) + scaled_percentage = (100 / 255) * battery_percentage_ns + + print("{0:.1f}%".format(scaled_percentage)) + + except ValueError as ex: + print("Failed to get battery percentage.\n{0}".format(ex), file=sys.stderr) + sys.exit(1) + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/is_charging.py b/openrazer/scripts/razer_mouse/driver/is_charging.py new file mode 100644 index 00000000..21b62c7b --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/is_charging.py @@ -0,0 +1,53 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import sys + + +def parse_args(): + parser = argparse.ArgumentParser(description="Get charging status") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + is_charging_filepath = os.path.join(mouse_dir, "is_charging") + with open(is_charging_filepath, 'r') as is_charging_file: + try: + is_charging = int(is_charging_file.read().strip()) + + if is_charging: + print("charging") + else: + print("not charging") + + except ValueError as ex: + print("Failed to get charging status.\n{0}".format(ex), file=sys.stderr) + sys.exit(1) + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/low_battery_threshold.py b/openrazer/scripts/razer_mouse/driver/low_battery_threshold.py new file mode 100644 index 00000000..bc7c726b --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/low_battery_threshold.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the low battery threshold") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--threshold', required=True, type=int, help="Threshold (1-25)") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + threshold = clamp_to_min_max(args.threshold, 1, 25) + threshold_scaled = clamp_to_u8(int(round((255 / 100) * threshold, 0))) + byte_string = bytes(str(threshold_scaled), 'utf-8') # Convert string to bytestring + + low_battery_threshold_filepath = os.path.join(mouse_dir, "set_low_battery_threshold") + with open(low_battery_threshold_filepath, 'wb') as low_battery_threshold_file: + low_battery_threshold_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/mouse_idle_time.py b/openrazer/scripts/razer_mouse/driver/mouse_idle_time.py new file mode 100644 index 00000000..0fa34695 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/mouse_idle_time.py @@ -0,0 +1,62 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the mouse idle time") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--timeout', required=True, type=int, help="Seconds (60-900)") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + seconds = clamp_to_min_max(args.seconds, 60, 900) + byte_string = bytes(str(seconds), 'utf-8') # Convert string to bytestring + + mouse_idle_time_filepath = os.path.join(mouse_dir, "set_idle_time") + with open(mouse_idle_time_filepath, 'wb') as mouse_idle_time_file: + mouse_idle_time_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/reactive_effect.py b/openrazer/scripts/razer_mouse/driver/reactive_effect.py new file mode 100644 index 00000000..15db6d76 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/reactive_effect.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the reactive effect") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--speed', required=True, type=int, help="Random breathing effect") + parser.add_argument('--colour', required=True, nargs=3, metavar=("R", "G", "B"), type=int, help="Reactive colour effect") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + speed = clamp_to_min_max(args.speed, 1, 3) + values = map(clamp_to_u8, args.colour) + byte_string = struct.pack(">BBBB", speed, *values) + + reactive_mode_filepath = os.path.join(mouse_dir, "mode_reactive") + with open(reactive_mode_filepath, 'wb') as reactive_mode_file: + reactive_mode_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/set_charging_colour.py b/openrazer/scripts/razer_mouse/driver/set_charging_colour.py new file mode 100644 index 00000000..4a875c31 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/set_charging_colour.py @@ -0,0 +1,58 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_u8(value): + if value > 255: + value = 255 + elif value < 0: + value = 0 + return value + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the charging colour") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--colour', required=True, nargs=3, metavar=("R", "G", "B"), type=int, help="Charging colour") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + values = map(clamp_to_u8, args.colour) + byte_string = struct.pack(">BBB", *values) + + set_charging_colour_filepath = os.path.join(mouse_dir, "set_charging_colour") + with open(set_charging_colour_filepath, 'wb') as set_charging_colour_file: + set_charging_colour_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/set_charging_effect.py b/openrazer/scripts/razer_mouse/driver/set_charging_effect.py new file mode 100644 index 00000000..70baea5d --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/set_charging_effect.py @@ -0,0 +1,66 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the wave effect") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--effect', required=True, type=int, help="Set whether or not to use static colour or last mouse effect for charging. 0 use mouse effect, 1 use colour") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + number = clamp_to_min_max(args.effect, 0, 1) + + if number: + byte_string = struct.pack(">B", 0x01) + else: + byte_string = struct.pack(">B", 0x00) + + set_charging_effect_filepath = os.path.join(mouse_dir, "set_charging_effect") + with open(set_charging_effect_filepath, 'wb') as set_charging_effect_file: + set_charging_effect_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/set_mouse_dpi.py b/openrazer/scripts/razer_mouse/driver/set_mouse_dpi.py new file mode 100644 index 00000000..0fac07fc --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/set_mouse_dpi.py @@ -0,0 +1,67 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the mouse DPI") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--dpi_x', required=True, type=int, help="DPI on the X axis (100, 30000)") + parser.add_argument('--dpi_y', type=int, help="DPI on the Y axis (if omitted, dpi_x is used), (100, 30000)") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + dpi_x = clamp_to_min_max(args.dpi_x, 100, 30000) + if args.dpi_y is None: + byte_string = struct.pack(">H", dpi_x) + else: + dpi_y = clamp_to_min_max(args.dpi_y, 100, 30000) + byte_string = struct.pack(">HH", dpi_x, dpi_y) + + set_mouse_dpi_filepath = os.path.join(mouse_dir, "dpi") + with open(set_mouse_dpi_filepath, 'wb') as set_mouse_dpi_file: + set_mouse_dpi_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/spectrum_effect.py b/openrazer/scripts/razer_mouse/driver/spectrum_effect.py new file mode 100644 index 00000000..7e09b329 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/spectrum_effect.py @@ -0,0 +1,59 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the spectrum effect") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + byte_string = struct.pack(">B", 0x01) + + spectrum_mode_filepath = os.path.join(mouse_dir, "mode_spectrum") + with open(spectrum_mode_filepath, 'wb') as spectrum_mode_file: + spectrum_mode_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/static_effect.py b/openrazer/scripts/razer_mouse/driver/static_effect.py new file mode 100644 index 00000000..de94972c --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/static_effect.py @@ -0,0 +1,62 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the static effect") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--colour', required=True, nargs=3, metavar=("R", "G", "B"), type=int, help="Static colour") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + values = map(clamp_to_u8, args.colour) + byte_string = struct.pack(">BBB", *values) + + static_mode_filepath = os.path.join(mouse_dir, "mode_static") + with open(static_mode_filepath, 'wb') as static_mode_file: + static_mode_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/wave_effect.py b/openrazer/scripts/razer_mouse/driver/wave_effect.py new file mode 100644 index 00000000..a34332b2 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/wave_effect.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the wave effect") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--direction', required=True, choices=('up', 'down'), help="Wave effect direction") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + if args.direction == 'up': + byte_string = b'1' + else: + byte_string = b'2' + + wave_mode_filepath = os.path.join(mouse_dir, "mode_wave") + with open(wave_mode_filepath, 'wb') as wave_mode_file: + wave_mode_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/razer_mouse/driver/wireless_brightness.py b/openrazer/scripts/razer_mouse/driver/wireless_brightness.py new file mode 100644 index 00000000..6e9f8979 --- /dev/null +++ b/openrazer/scripts/razer_mouse/driver/wireless_brightness.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 +import argparse +import glob +import os +import struct +import sys + + +def clamp_to_min_max(value, min, max): + if value > max: + value = max + elif value < min: + value = min + return value + + +def clamp_to_u8(value): + return clamp_to_min_max(value, 0, 255) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Set the wireless brightness") + parser.add_argument('-d', '--device', type=str, help="Device string like \"0003:1532:0045.000C\"") + + parser.add_argument('--brightness', required=True, type=int, help="Brightness (0-100)") + + args = parser.parse_args() + return args + + +def run(): + args = parse_args() + + if args.device is None: + mouse_dirs = glob.glob(os.path.join('/sys/bus/hid/drivers/razermouse/', "*:*:*.*")) + + if len(mouse_dirs) > 1: + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + if len(mouse_dirs) < 1: + print("No mouse directories found. Make sure the driver is binded", file=sys.stderr) + sys.exit(1) + + mouse_dir = mouse_dirs[0] + else: + mouse_dir = os.path.join('/sys/bus/hid/drivers/razermouse/', args.device) + + if not os.path.isdir(mouse_dir): + print("Multiple mouse directories found. Rerun with -d", file=sys.stderr) + sys.exit(1) + + brightness = clamp_to_min_max(args.brightness, 0, 100) + brightness_scaled = clamp_to_u8(int(round((255 / 100) * brightness, 0))) + byte_string = bytes(str(brightness_scaled), 'utf-8') # Convert string to bytestring + + wireless_brightness_filepath = os.path.join(mouse_dir, "set_wireless_brightness") + with open(wireless_brightness_filepath, 'wb') as wireless_brightness_file: + wireless_brightness_file.write(byte_string) + print("Done") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/setup_fake_devices.sh b/openrazer/scripts/setup_fake_devices.sh new file mode 100755 index 00000000..4cfdff53 --- /dev/null +++ b/openrazer/scripts/setup_fake_devices.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# +# A simple script to choose what devices +# you want to fake (for debugging) +# + +whereami="$(dirname "$0")" + +device_cfg_files=$(ls "$whereami/../pylib/openrazer/_fake_driver/"*.cfg) +config_dir="/tmp/daemon_config/" +test_dir="/tmp/daemon_test" + +# Check zenity is installed +command -v zenity >/dev/null 2>&1 +if [ $? != 0 ]; then + echo "This script requires 'zenity', but was not found." + exit 1 +fi + +# Check if x-terminal-emulator exists (only on Debian & derivatives) +command -v x-terminal-emulator >/dev/null 2>&1 +if [ $? == 0 ]; then + terminal_cmd="x-terminal-emulator -e" +else + command -v xterm >/dev/null 2>&1 + if [ $? != 0 ]; then + text="Neither x-terminal-emulator nor xterm was found in \$PATH. Exiting." + echo $text + zenity --error --text="$text" + exit 1 + fi + terminal_cmd="xterm -e" +fi + +devices="" +for cfg in $device_cfg_files; do + cfg_file=$(basename "$cfg") + devices="$devices 0 ${cfg_file%.*}" +done + +options=$(zenity --list --multiple --checklist \ + --print-column=2 --separator=" " \ + --height=250 --width=400 \ + --title="Create Fake OpenRazer Device" \ + --text="Select the devices to simulate." \ + --column "" --column "Device" \ + $devices) + +# Quit if cancelled +if [ ! $? == 0 ]; then + exit 1 +fi + +# Prepare fake devices. +mkdir $config_dir/{,data,logs} +mkdir $test_dir +$terminal_cmd "$whereami/create_fake_device.py" --dest "$test_dir" $options & + +# Kill openrazer-daemon if it is running already. +pkill -e openrazer-daemon + +# Start the daemon in a new terminal window. +$terminal_cmd "$whereami/../daemon/run_openrazer_daemon.py" --verbose -F --run-dir "$config_dir/data" --log-dir "$config_dir/logs" --test-dir "$test_dir" diff --git a/openrazer/scripts/troubleshoot.sh b/openrazer/scripts/troubleshoot.sh new file mode 100755 index 00000000..86ca6d99 --- /dev/null +++ b/openrazer/scripts/troubleshoot.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +dkms_name="openrazer-driver" # TODO Rename when dkms module is renamed. + +echo "This script will now try to determine why the razer driver isn't working correctly." + +# Step 1 - check if there is a razer device connected. +lsusb=$(lsusb | grep '1532:') +if [ -z "$lsusb" ]; then + echo "ERROR: Linux doesn't see any Razer device connected. Make sure it is connected! Exiting." + exit 1 +fi + +# Step 2 - check if a module is already loaded. +lsmod=$(lsmod | grep razer) +if [ -z "$lsmod" ]; then + echo "INFO: There is no kernel module loaded." +fi + +# Step 3 - check if the module can load correctly +echo "Please enter your 'sudo' password for privileged operations." +module_name="razerkbd" +modprobe=$(sudo modprobe $module_name 2>&1) +if [ $? != 0 ]; then + if [[ $modprobe == *"FATAL: Module $module_name not found"* ]]; then + echo "ERROR: The kernel module wasn't found. Trying to find out why." + dkms_status=$(sudo dkms status $dkms_name) + if [ -z "$dkms_status" ]; then + echo "ERROR: DKMS module isn't installed. Trying to install now." + dkms_version=$(cat /usr/src/$dkms_name-*/dkms.conf | grep PACKAGE_VERSION | cut -d '"' -f2) + # TODO Check error code on command "cat /usr/..." + dkms_install=$(sudo dkms install $dkms_name/$dkms_version) + if [ $? != 0 ]; then + if [[ $dkms_install == *"Error! Could not find module source directory."* ]]; then + echo "FATAL: Is the razer dkms package installed? Exiting." + exit 1 + elif [[ $dkms_install == *"Module openrazer-driver/$dkms_version already installed on kernel"* ]]; then + echo "FATAL: The dkms module is installed, but could not be loaded. Exiting." + exit 1 + fi + else + echo "INFO: dkms module should be installed now. Output of command:" + echo $dkms_install + echo "INFO: Please call the script again to check further. Exiting." + exit 0 + fi + fi + elif [[ $modprobe == *"ERROR: could not insert '$module_name': Required key not available"* ]]; then + echo "ERROR: The module couldn't be loaded due to secure boot being enabled. Please disable secure boot in your BIOS/UEFI and try again. Exiting." + exit 1 + else + echo "FATAL: Unknown error. The output will be echo'ed below. Exiting." + echo $modprobe + exit 1 + fi +fi + +# Step 4 - check the daemon +log_dir=/tmp/razer_logs +mkdir -p $log_dir +openrazer-daemon -r -v --log-dir=$log_dir +sleep 3 +daemon_output=$(cat $log_dir/razer.log) +if [ ! -z "$(echo $daemon_output | grep 'PermissionError: [Errno 13] Permission denied')" ]; then + echo "ERROR: The current user doesn't have permission to access the driver files. Checking why." + file=$(echo $daemon_output | cut -d "'" -f4) + owning_group=$(stat -c '%G' $file) + if [ $owning_group != "plugdev" ]; then + echo "FATAL: Because of some reason, the owner of the file isn't plugdev, as it should be. Exiting." + exit 1 + fi + group_plugdev=$(groups | grep plugdev) + if [ -z "$group_plugdev" ]; then + echo "FATAL: The current isn't member of the group 'plugdev'. Please fix this by running 'sudo gpasswd -a $USER plugdev'. Exiting." + exit 1 + fi +fi + +# Step 5 - check if the pylib sees the device(s) +pylib_len=$(python -c "from openrazer.client import DeviceManager; a = DeviceManager(); print(len(a.devices))") +if [ "$pylib_len" == 0 ]; then + echo "FATAL: The device was not recognized by the python library. Exiting." + exit 1 +fi + +# Everything alright (probably) +echo "The script didn't find an error. If you still think something's wrong, please create an issue on the GitHub page. Exiting." +exit 0 diff --git a/openrazer/scripts/wireshark/pcap_extract.py b/openrazer/scripts/wireshark/pcap_extract.py new file mode 100644 index 00000000..df76512c --- /dev/null +++ b/openrazer/scripts/wireshark/pcap_extract.py @@ -0,0 +1,83 @@ +#!/usr/bin/python3 +""" +This script takes in CSV files generated from wireshark's "Export Packet Dissections > as CSV" option. + +And prints out nice output. +""" +import argparse +import csv + +FIELDS = { + 'status': 0, + 'transaction_id': 1, + 'packet_num': (2, 4), + 'proto_type': 4, + 'data_size': 5, + 'class': 6, + 'command': 7, + 'params': (8, 24) +} + + +def expand_payload(payload): + """ + Converts a payload string to a nice format + + :param payload: String of hex digits + :type payload: str + + :return: Dictionary + :rtype dict + """ + chunks = [payload[i:i + 2] for i in range(0, len(payload), 2)] + + result = {} + + for header, num_range in FIELDS.items(): + if isinstance(num_range, tuple): + result[header] = ''.join(chunks[num_range[0]:num_range[1]]) + else: + result[header] = chunks[num_range] + + return result + + +def parse_args(): + """ + Parses command line arguments + + :return: Argparse arguments object + """ + parser = argparse.ArgumentParser(description="Extracts info from CSV") + parser.add_argument("file", metavar='FILE', type=str, help="CSV file") + + return parser.parse_args() + + +def run(): + """ + Main function + """ + args = parse_args() + + data = [] + + with open(args.file, 'r', newline='') as csv_file: + csv_object = csv.DictReader(csv_file, delimiter=',', quotechar='"') + for line in csv_object: + if line['Leftover Capture Data'] == '': + continue + + # Now we have data + data.append(expand_payload(line['Leftover Capture Data'])) + + format_string = "{0:<6} {1:<2} {2:<10} {3:<4} {4:<5} {5:<7} {6}" + print(format_string.format('Status', 'ID', 'Packet Num', 'Size', 'Class', 'Command', 'Params')) + for frame in data: + print(format_string.format(frame['status'], frame['transaction_id'], frame['packet_num'], + frame['data_size'], frame['class'], frame['command'], frame['params'])) + print("") + + +if __name__ == '__main__': + run() diff --git a/openrazer/scripts/wireshark/razer.lua b/openrazer/scripts/wireshark/razer.lua new file mode 100644 index 00000000..fec667de --- /dev/null +++ b/openrazer/scripts/wireshark/razer.lua @@ -0,0 +1,113 @@ +-- Thanks to karlp for making a nice lua protocol example for USB https://github.com/karlp/swopy +-- +-- Copyright 2015 Terri Cain +-- To install put in ~/.wireshark/plugins/FILENAME.lua +-- or ran with wireshark -X lua_script:FILENAME.lua +-- +-- Could of binded it to the Razer USB Vendor:Product ID but when wiresharking USB comms to virtualbox +-- wireshark can miss the VID,PID declaration and then the dissector wouldn't apply so just use it when +-- dissecting razer traffic, don't use it all the time as it'll apply to all usb-control requests + +razer_proto = Proto("razer", "Razer Protocol") + +local req_types = { + [0x00] = "REQUEST", + [0x02] = "RESPONSE", +} + +local f = razer_proto.fields +f.f_status = ProtoField.uint8("razer.status", "Request Type", base.HEX, req_types) -- 1b +f.f_id = ProtoField.uint8("razer.id", "ID", base.HEX) -- 1b Possibly I2C range +f.f_remaining_packets = ProtoField.uint16("razer.remaining_packets", "Remaining Packets", base.DEC) -- 2b +f.f_protocol_type = ProtoField.uint8("razer.protocol_type", "Protocol Type", base.HEX) -- 1b +f.f_number_parameter_bytes = ProtoField.uint8("razer.num_params", "Number of parameters", base.HEX) -- 1b Number of bytes after command byte +f.f_command_class = ProtoField.uint8("razer.command_class", "Command Class", base.HEX) -- 1b Command byte +f.f_command_id = ProtoField.uint8("razer.command_id", "Command ID", base.HEX) -- 1b Sub Command byte +f.f_command_params = ProtoField.bytes("razer.command_params", "Command parameters", base.SPACE) -- 80b Params +f.f_crc = ProtoField.uint8("razer.crc", "CRC", base.HEX) -- 1b CRC checksum +f.f_end_marker = ProtoField.uint8("razer.end", "End", base.HEX) -- 1b End marker + + +local f_usb_ep_num = Field.new("usb.endpoint_address.number") -- should be 0 +local f_usb_ep_dir = Field.new("usb.endpoint_address.direction") -- 1 IN, 0 OUT +local f_data_len = Field.new("usb.data_len") -- should be 90 +local f_urb_len = Field.new("usb.urb_len") -- should be 90 + +local function getstring(fi) + local ok, val = pcall(tostring, fi) + if not ok then val = "(unknown)" end + return val +end + +-- write32 doesn't have a response on the in endpoint, it tweaks decoding on the _out_ endpoint +local responses = { + NOTSET = 1, READMEM32 = 2, GENERIC = 3, READDEBUG = 4, + WRITEMEM32 = 5, + TRACECOUNT = 6 +} + +local expected = responses.NOTSET + +function razer_proto.dissector(buffer, pinfo, tree) + + --[[This was very helpful for working out the field names I could use with Field.new() + local fields = { all_field_infos() } + for ix, finfo in ipairs(fields) do + print(string.format("ix=%d, finfo.name = %s, finfo.value=%s", ix, finfo.name, getstring(finfo))) + end + print("\n")--]] + + local data_length = f_data_len() + local data_direction = f_usb_ep_dir() + local urb_length = f_urb_len() + + + if (data_length.value == 90 and urb_length.value == 90) then + pinfo.cols["protocol"] = "Razer" + + -- seek to the last 90 bytes + local offset = buffer:len() - 90 + local t_razer = tree:add(razer_proto, buffer()) + + if (data_direction.value == 0) then + pinfo.cols["info"]:append("Request") + else + pinfo.cols["info"]:append("Response") + end + + -- Add REQ,RES byte + t_razer:add(f.f_status, buffer(offset, 1)) + offset = offset + 1 + -- Add ID + t_razer:add(f.f_id, buffer(offset, 1)) + offset = offset + 1 + -- Add Remaining packets + t_razer:add(f.f_remaining_packets, buffer(offset, 2)) + offset = offset + 2 + -- Add Protocol Type + t_razer:add(f.f_protocol_type, buffer(offset, 1)) + offset = offset + 1 + -- Add Number of parameters bytes + local num_params = buffer(offset, 1):le_uint() + t_razer:add(f.f_number_parameter_bytes, buffer(offset, 1)) -- specified buffer here instead of num params so it highlights in wireshark + offset = offset + 1 + -- Add Command class + t_razer:add(f.f_command_class, buffer(offset, 1)) + offset = offset + 1 + -- Add Command ID + t_razer:add(f.f_command_id, buffer(offset, 1)) + offset = offset + 1 + -- Add command params + t_razer:add(f.f_command_params, buffer(offset, num_params)) + offset = offset + 80 -- skip to the end + -- Add CRC + t_razer:add(f.f_crc, buffer(offset, 1)) + offset = offset + 1 + -- Add end + t_razer:add(f.f_end_marker, buffer(offset, 1)) + offset = offset + 1 + end +end + +usb_table = DissectorTable.get("usb.control") +usb_table:add(0xffff, razer_proto) diff --git a/package.json b/package.json index cee0b365..1e51f28c 100644 --- a/package.json +++ b/package.json @@ -29,13 +29,17 @@ "tinycolor2": "^1.4.2" }, "devDependencies": { - "@babel/preset-react": "^7.14.5", + "@babel/core": "^7.28.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/preset-env": "^7.28.0", + "@babel/preset-react": "^7.27.1", + "@electron/universal": "^1.2.1", "babel-loader": "^8.1.0", + "browserslist": "^4.25.1", "electron": "^11.5.0", "electron-builder": "^23.3.3", "electron-builder-notarize": "^1.2.0", "electron-webpack": "^2.8.2", - "@electron/universal": "^1.2.1", "mini-css-extract-plugin": "^0.9.0", "native-ext-loader": "^2.3.0", "node-gyp": "^8.2.0", @@ -88,7 +92,8 @@ "darwin" ], "arches": [ - "x64", "arm64" + "x64", + "arm64" ] } } diff --git a/src/BasiliskDeviceDetection.ps1 b/src/BasiliskDeviceDetection.ps1 new file mode 100644 index 00000000..600b4ec9 --- /dev/null +++ b/src/BasiliskDeviceDetection.ps1 @@ -0,0 +1,40 @@ +Write-Host "=== Basilisk V3 X HyperSpeed Detection ===" -ForegroundColor Green + +# Check for the specific device +$basilisk = Get-PnpDevice | Where-Object { + ($_.HardwareID -like "*VID_1532*PID_00B9*") -or + ($_.FriendlyName -like "*Basilisk*") +} + +if ($basilisk) { + Write-Host "✓ Basilisk Found!" -ForegroundColor Green + $basilisk | ForEach-Object { + Write-Host " Name: $($_.FriendlyName)" -ForegroundColor Yellow + Write-Host " Status: $($_.Status)" -ForegroundColor Cyan + # Fix for null array issue - check if HardwareID exists and is not empty + if ($_.HardwareID -and $_.HardwareID.Count -gt 0) { + Write-Host " Hardware ID: $($_.HardwareID[0])" -ForegroundColor Gray + } else { + Write-Host " Hardware ID: Not available" -ForegroundColor Gray + } + } +} else { + Write-Host "✗ Basilisk not found. Checking all Razer devices..." -ForegroundColor Red + $razer = Get-PnpDevice | Where-Object {$_.FriendlyName -like "*Razer*"} + if ($razer) { + $razer | ForEach-Object { + Write-Host " - $($_.FriendlyName)" -ForegroundColor White + } + } else { + Write-Host "No Razer devices detected!" -ForegroundColor Red + } +} + +# Check USB devices +Write-Host "`nUSB Device Check:" -ForegroundColor Yellow +$usb = Get-WmiObject Win32_USBHub | Where-Object {$_.DeviceID -like "*VID_1532*PID_00B9*"} +if ($usb) { + Write-Host "✓ USB connection confirmed" -ForegroundColor Green +} else { + Write-Host "✗ USB connection not detected" -ForegroundColor Red +} \ No newline at end of file diff --git a/src/devices/basilisk_v3_x_hyperspeed.json b/src/devices/basilisk_v3_x_hyperspeed.json new file mode 100644 index 00000000..ea19deff --- /dev/null +++ b/src/devices/basilisk_v3_x_hyperspeed.json @@ -0,0 +1,22 @@ +{ + "name": "Razer Basilisk V3 X HyperSpeed", + "productId": "0x00B9", + "mainType": "mouse", + "image": "https://assets.razerzone.com/eeimages/support/products/1589/1589_basilisk_x__hyperspeed.png", + "features": null, + "featuresMissing": ["oldMouseEffects", "reactive", "breathe"], + "featuresConfig": [ + { + "dpi": { + "max": 26000 + } + }, + { + "mouseBrightness": { + "enabledLeft": false, + "enabledRight": false, + "enabledScroll": true + } + } + ] +} \ No newline at end of file diff --git a/src/main/device/razerdevice.js b/src/main/device/razerdevice.js index 0adf2b32..134cf9c8 100644 --- a/src/main/device/razerdevice.js +++ b/src/main/device/razerdevice.js @@ -17,7 +17,7 @@ export class RazerDevice { r: 255, g: 255, b: 0, - } + }, }; this.activeMode = null; this.activeModeArguments = null; @@ -29,17 +29,16 @@ export class RazerDevice { } getSettingsKey() { - return 'razer_'+this.productId; + return 'razer_' + this.productId; } getDefaultSettings() { return { - customColor1: this.defaultColorSettings + customColor1: this.defaultColorSettings, }; } - refresh() { - } + refresh() {} destroy() { this.addon = null; @@ -53,8 +52,8 @@ export class RazerDevice { getState() { return { mode: this.activeMode, - args: this.activeModeArguments - } + args: this.activeModeArguments, + }; } resetToState(state) { @@ -65,28 +64,63 @@ export class RazerDevice { return typeof this.getFeature(featureIdentifier) !== 'undefined'; } getFeature(featureIdentifier) { - return this.features.find(feature => feature.featureIdentifier === featureIdentifier); + return this.features.find( + (feature) => feature.featureIdentifier === featureIdentifier + ); } //override in device types setModeNone() { - this.setModeState('none'); + try { + this.setModeState('none'); + } catch (error) { + throw new Error(`Failed to set mode none: ${error.message}`); + } } + setModeStaticNoStore(color) { - this.setModeState('staticNoStore', color); + try { + if (!color) { + throw new Error('Color parameter is required'); + } + this.setModeState('staticNoStore', color); + } catch (error) { + throw new Error(`Failed to set static no store mode: ${error.message}`); + } } + setModeStatic(color) { - this.setModeState('static', color); + try { + if (!color) { + throw new Error('Color parameter is required'); + } + this.setModeState('static', color); + } catch (error) { + throw new Error(`Failed to set static mode: ${error.message}`); + } } setSpectrum() { - this.setModeState('spectrum'); + try { + this.setModeState('spectrum'); + } catch (error) { + throw new Error(`Failed to set spectrum mode: ${error.message}`); + } } + setBreathe(color) { - this.setModeState('breathe', color); + try { + if (!color) { + throw new Error('Color parameter is required'); + } + this.setModeState('breathe', color); + } catch (error) { + throw new Error(`Failed to set breathe mode: ${error.message}`); + } } - /*protected*/ setModeState(mode, modeArguments = null) { + /*protected*/ + setModeState(mode, modeArguments = null) { this.activeMode = mode; this.activeModeArguments = modeArguments; } @@ -99,10 +133,10 @@ export class RazerDevice { const ignoreProperties = this.getSerializeIgnoredProperties(); const serializedDevice = {}; Object.entries(this) - .filter(([key]) => !ignoreProperties.find(ignored => ignored === key)) + .filter(([key]) => !ignoreProperties.find((ignored) => ignored === key)) .forEach(([key, value]) => { serializedDevice[key] = value; - }) + }); serializedDevice['state'] = this.getState(); return serializedDevice; } diff --git a/yarn.lock b/yarn.lock index fa88d07b..a1bb796c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,6 +19,14 @@ dependencies: "@jridgewell/trace-mapping" "^0.3.0" +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" @@ -26,11 +34,46 @@ dependencies: "@babel/highlight" "^7.16.7" +"@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== +"@babel/compat-data@^7.27.2", "@babel/compat-data@^7.27.7", "@babel/compat-data@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.0.tgz#9fc6fd58c2a6a15243cd13983224968392070790" + integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw== + +"@babel/core@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.0.tgz#55dad808d5bf3445a108eefc88ea3fdf034749a4" + integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.27.3" + "@babel/helpers" "^7.27.6" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.0" + "@babel/types" "^7.28.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/core@^7.9.0": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.9.tgz#6bae81a06d95f4d0dec5bb9d74bbc1f58babdcfe" @@ -61,6 +104,17 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.0.tgz#9cc2f7bd6eb054d77dc66c2664148a0c5118acd2" + integrity sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg== + dependencies: + "@babel/parser" "^7.28.0" + "@babel/types" "^7.28.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + "@babel/helper-annotate-as-pure@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" @@ -68,6 +122,13 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-annotate-as-pure@^7.27.1", "@babel/helper-annotate-as-pure@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5" + integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg== + dependencies: + "@babel/types" "^7.27.3" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" @@ -86,6 +147,17 @@ browserslist "^4.17.5" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz#71835d7fb9f38bd9f1378e40a4c0902fdc2ea49d" @@ -99,6 +171,19 @@ "@babel/helper-replace-supers" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" +"@babel/helper-create-class-features-plugin@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz#5bee4262a6ea5ddc852d0806199eb17ca3de9281" + integrity sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/traverse" "^7.27.1" + semver "^6.3.1" + "@babel/helper-create-regexp-features-plugin@^7.16.7": version "7.17.0" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1" @@ -107,6 +192,15 @@ "@babel/helper-annotate-as-pure" "^7.16.7" regexpu-core "^5.0.1" +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz#05b0882d97ba1d4d03519e4bce615d70afa18c53" + integrity sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + regexpu-core "^6.2.0" + semver "^6.3.1" + "@babel/helper-define-polyfill-provider@^0.3.1": version "0.3.1" resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" @@ -121,6 +215,17 @@ resolve "^1.14.2" semver "^6.1.2" +"@babel/helper-define-polyfill-provider@^0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz#742ccf1cb003c07b48859fc9fa2c1bbe40e5f753" + integrity sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg== + dependencies: + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-plugin-utils" "^7.27.1" + debug "^4.4.1" + lodash.debounce "^4.0.8" + resolve "^1.22.10" + "@babel/helper-environment-visitor@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" @@ -143,6 +248,11 @@ "@babel/template" "^7.16.7" "@babel/types" "^7.17.0" +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + "@babel/helper-hoist-variables@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" @@ -157,6 +267,14 @@ dependencies: "@babel/types" "^7.17.0" +"@babel/helper-member-expression-to-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44" + integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + "@babel/helper-module-imports@7.0.0-beta.35": version "7.0.0-beta.35" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.35.tgz#308e350e731752cdb4d0f058df1d704925c64e0a" @@ -172,6 +290,14 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + "@babel/helper-module-transforms@^7.16.7", "@babel/helper-module-transforms@^7.17.7": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" @@ -186,6 +312,15 @@ "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" +"@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz#db0bbcfba5802f9ef7870705a7ef8788508ede02" + integrity sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.3" + "@babel/helper-optimise-call-expression@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" @@ -193,11 +328,23 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-optimise-call-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" + integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== + dependencies: + "@babel/types" "^7.27.1" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== +"@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + "@babel/helper-remap-async-to-generator@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" @@ -207,6 +354,15 @@ "@babel/helper-wrap-function" "^7.16.8" "@babel/types" "^7.16.8" +"@babel/helper-remap-async-to-generator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz#4601d5c7ce2eb2aea58328d43725523fcd362ce6" + integrity sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-wrap-function" "^7.27.1" + "@babel/traverse" "^7.27.1" + "@babel/helper-replace-supers@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" @@ -218,6 +374,15 @@ "@babel/traverse" "^7.16.7" "@babel/types" "^7.16.7" +"@babel/helper-replace-supers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0" + integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/traverse" "^7.27.1" + "@babel/helper-simple-access@^7.17.7": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" @@ -232,6 +397,14 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" + integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + "@babel/helper-split-export-declaration@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" @@ -239,16 +412,31 @@ dependencies: "@babel/types" "^7.16.7" +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + "@babel/helper-validator-identifier@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + "@babel/helper-validator-option@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + "@babel/helper-wrap-function@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" @@ -259,6 +447,15 @@ "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" +"@babel/helper-wrap-function@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz#b88285009c31427af318d4fe37651cd62a142409" + integrity sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ== + dependencies: + "@babel/template" "^7.27.1" + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + "@babel/helpers@^7.17.9": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.9.tgz#b2af120821bfbe44f9907b1826e168e819375a1a" @@ -268,6 +465,14 @@ "@babel/traverse" "^7.17.9" "@babel/types" "^7.17.0" +"@babel/helpers@^7.27.6": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.2.tgz#80f0918fecbfebea9af856c419763230040ee850" + integrity sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.2" + "@babel/highlight@^7.16.7": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.9.tgz#61b2ee7f32ea0454612def4fccdae0de232b73e3" @@ -282,6 +487,28 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef" integrity sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg== +"@babel/parser@^7.27.2", "@babel/parser@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.0.tgz#979829fbab51a29e13901e5a80713dbcb840825e" + integrity sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g== + dependencies: + "@babel/types" "^7.28.0" + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz#61dd8a8e61f7eb568268d1b5f129da3eee364bf9" + integrity sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz#43f70a6d7efd52370eefbdf55ae03d91b293856d" + integrity sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" @@ -289,6 +516,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz#beb623bd573b8b6f3047bd04c32506adc3e58a72" + integrity sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" @@ -298,6 +532,23 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-proposal-optional-chaining" "^7.16.7" +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz#e134a5479eb2ba9c02714e8c1ebf1ec9076124fd" + integrity sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-optional-chaining" "^7.27.1" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz#bb1c25af34d75115ce229a1de7fa44bf8f955670" + integrity sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.27.1" + "@babel/plugin-proposal-async-generator-functions@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" @@ -408,6 +659,11 @@ "@babel/helper-create-class-features-plugin" "^7.16.10" "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + "@babel/plugin-proposal-private-property-in-object@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" @@ -461,6 +717,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-syntax-import-assertions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz#88894aefd2b03b5ee6ad1562a7c8e1587496aecd" + integrity sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-import-attributes@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" + integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" @@ -468,12 +738,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" - integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== +"@babel/plugin-syntax-jsx@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.27.1" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -531,6 +801,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-transform-arrow-functions@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" @@ -538,6 +816,22 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-arrow-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz#6e2061067ba3ab0266d834a9f94811196f2aba9a" + integrity sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-async-generator-functions@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz#1276e6c7285ab2cd1eccb0bc7356b7a69ff842c2" + integrity sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-remap-async-to-generator" "^7.27.1" + "@babel/traverse" "^7.28.0" + "@babel/plugin-transform-async-to-generator@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" @@ -547,6 +841,15 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-remap-async-to-generator" "^7.16.8" +"@babel/plugin-transform-async-to-generator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz#9a93893b9379b39466c74474f55af03de78c66e7" + integrity sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-remap-async-to-generator" "^7.27.1" + "@babel/plugin-transform-block-scoped-functions@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" @@ -554,6 +857,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-block-scoped-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz#558a9d6e24cf72802dd3b62a4b51e0d62c0f57f9" + integrity sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-block-scoping@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" @@ -561,6 +871,29 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-block-scoping@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz#e7c50cbacc18034f210b93defa89638666099451" + integrity sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-class-properties@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz#dd40a6a370dfd49d32362ae206ddaf2bb082a925" + integrity sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-class-static-block@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz#7e920d5625b25bbccd3061aefbcc05805ed56ce4" + integrity sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-classes@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" @@ -575,6 +908,18 @@ "@babel/helper-split-export-declaration" "^7.16.7" globals "^11.1.0" +"@babel/plugin-transform-classes@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz#12fa46cffc32a6e084011b650539e880add8a0f8" + integrity sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-globals" "^7.28.0" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + "@babel/traverse" "^7.28.0" + "@babel/plugin-transform-computed-properties@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" @@ -582,6 +927,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-computed-properties@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz#81662e78bf5e734a97982c2b7f0a793288ef3caa" + integrity sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/template" "^7.27.1" + "@babel/plugin-transform-destructuring@^7.16.7": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" @@ -589,6 +942,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-destructuring@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz#0f156588f69c596089b7d5b06f5af83d9aa7f97a" + integrity sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.28.0" + "@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" @@ -597,6 +958,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-dotall-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz#aa6821de864c528b1fecf286f0a174e38e826f4d" + integrity sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-duplicate-keys@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" @@ -604,6 +973,36 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-duplicate-keys@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz#f1fbf628ece18e12e7b32b175940e68358f546d1" + integrity sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz#5043854ca620a94149372e69030ff8cb6a9eb0ec" + integrity sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-dynamic-import@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz#4c78f35552ac0e06aa1f6e3c573d67695e8af5a4" + integrity sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-explicit-resource-management@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz#45be6211b778dbf4b9d54c4e8a2b42fa72e09a1a" + integrity sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-destructuring" "^7.28.0" + "@babel/plugin-transform-exponentiation-operator@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" @@ -612,6 +1011,20 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-exponentiation-operator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz#fc497b12d8277e559747f5a3ed868dd8064f83e1" + integrity sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-export-namespace-from@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz#71ca69d3471edd6daa711cf4dfc3400415df9c23" + integrity sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-for-of@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" @@ -619,6 +1032,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-for-of@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz#bc24f7080e9ff721b63a70ac7b2564ca15b6c40a" + integrity sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-function-name@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" @@ -628,6 +1049,22 @@ "@babel/helper-function-name" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-function-name@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz#4d0bf307720e4dce6d7c30fcb1fd6ca77bdeb3a7" + integrity sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ== + dependencies: + "@babel/helper-compilation-targets" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/plugin-transform-json-strings@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz#a2e0ce6ef256376bd527f290da023983527a4f4c" + integrity sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-literals@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" @@ -635,6 +1072,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz#baaefa4d10a1d4206f9dcdda50d7d5827bb70b24" + integrity sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-logical-assignment-operators@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz#890cb20e0270e0e5bebe3f025b434841c32d5baa" + integrity sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-member-expression-literals@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" @@ -642,6 +1093,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-member-expression-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz#37b88ba594d852418e99536f5612f795f23aeaf9" + integrity sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-modules-amd@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" @@ -651,6 +1109,14 @@ "@babel/helper-plugin-utils" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-amd@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz#a4145f9d87c2291fe2d05f994b65dba4e3e7196f" + integrity sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-modules-commonjs@^7.16.8": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz#274be1a2087beec0254d4abd4d86e52442e1e5b6" @@ -661,6 +1127,14 @@ "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-commonjs@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz#8e44ed37c2787ecc23bdc367f49977476614e832" + integrity sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-modules-systemjs@^7.16.7": version "7.17.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" @@ -672,6 +1146,16 @@ "@babel/helper-validator-identifier" "^7.16.7" babel-plugin-dynamic-import-node "^2.3.3" +"@babel/plugin-transform-modules-systemjs@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz#00e05b61863070d0f3292a00126c16c0e024c4ed" + integrity sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.1" + "@babel/plugin-transform-modules-umd@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" @@ -680,6 +1164,14 @@ "@babel/helper-module-transforms" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-modules-umd@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz#63f2cf4f6dc15debc12f694e44714863d34cd334" + integrity sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": version "7.16.8" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" @@ -687,6 +1179,14 @@ dependencies: "@babel/helper-create-regexp-features-plugin" "^7.16.7" +"@babel/plugin-transform-named-capturing-groups-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz#f32b8f7818d8fc0cc46ee20a8ef75f071af976e1" + integrity sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-new-target@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" @@ -694,6 +1194,38 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-new-target@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz#259c43939728cad1706ac17351b7e6a7bea1abeb" + integrity sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz#4f9d3153bf6782d73dd42785a9d22d03197bc91d" + integrity sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-numeric-separator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz#614e0b15cc800e5997dadd9bd6ea524ed6c819c6" + integrity sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-object-rest-spread@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz#d23021857ffd7cd809f54d624299b8086402ed8d" + integrity sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA== + dependencies: + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-destructuring" "^7.28.0" + "@babel/plugin-transform-parameters" "^7.27.7" + "@babel/traverse" "^7.28.0" + "@babel/plugin-transform-object-super@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" @@ -702,6 +1234,29 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-replace-supers" "^7.16.7" +"@babel/plugin-transform-object-super@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz#1c932cd27bf3874c43a5cac4f43ebf970c9871b5" + integrity sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + +"@babel/plugin-transform-optional-catch-binding@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz#84c7341ebde35ccd36b137e9e45866825072a30c" + integrity sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-optional-chaining@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz#874ce3c4f06b7780592e946026eb76a32830454f" + integrity sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-parameters@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" @@ -709,6 +1264,30 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-parameters@^7.27.7": + version "7.27.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz#1fd2febb7c74e7d21cf3b05f7aebc907940af53a" + integrity sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-private-methods@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz#fdacbab1c5ed81ec70dfdbb8b213d65da148b6af" + integrity sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-private-property-in-object@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz#4dbbef283b5b2f01a21e81e299f76e35f900fb11" + integrity sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-property-literals@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" @@ -716,38 +1295,45 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" -"@babel/plugin-transform-react-display-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" - integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== +"@babel/plugin-transform-property-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz#07eafd618800591e88073a0af1b940d9a42c6424" + integrity sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-react-jsx-development@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz#43a00724a3ed2557ed3f276a01a929e6686ac7b8" - integrity sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A== +"@babel/plugin-transform-react-display-name@^7.27.1": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz#6f20a7295fea7df42eb42fed8f896813f5b934de" + integrity sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA== dependencies: - "@babel/plugin-transform-react-jsx" "^7.16.7" + "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-react-jsx@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1" - integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ== +"@babel/plugin-transform-react-jsx-development@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz#47ff95940e20a3a70e68ad3d4fcb657b647f6c98" + integrity sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.16.7" - "@babel/types" "^7.17.0" + "@babel/plugin-transform-react-jsx" "^7.27.1" -"@babel/plugin-transform-react-pure-annotations@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz#232bfd2f12eb551d6d7d01d13fe3f86b45eb9c67" - integrity sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA== +"@babel/plugin-transform-react-jsx@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz#1023bc94b78b0a2d68c82b5e96aed573bcfb9db0" + integrity sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw== dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-syntax-jsx" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/plugin-transform-react-pure-annotations@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz#339f1ce355eae242e0649f232b1c68907c02e879" + integrity sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" "@babel/plugin-transform-regenerator@^7.16.7": version "7.17.9" @@ -756,6 +1342,21 @@ dependencies: regenerator-transform "^0.15.0" +"@babel/plugin-transform-regenerator@^7.28.0": + version "7.28.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.1.tgz#bde80603442ff4bb4e910bc8b35485295d556ab1" + integrity sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-regexp-modifiers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz#df9ba5577c974e3f1449888b70b76169998a6d09" + integrity sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-reserved-words@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" @@ -763,6 +1364,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-reserved-words@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz#40fba4878ccbd1c56605a4479a3a891ac0274bb4" + integrity sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-shorthand-properties@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" @@ -770,6 +1378,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-shorthand-properties@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz#532abdacdec87bfee1e0ef8e2fcdee543fe32b90" + integrity sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-spread@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" @@ -778,6 +1393,14 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" +"@babel/plugin-transform-spread@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz#1a264d5fc12750918f50e3fe3e24e437178abb08" + integrity sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-sticky-regex@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" @@ -785,6 +1408,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-sticky-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz#18984935d9d2296843a491d78a014939f7dcd280" + integrity sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-template-literals@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" @@ -792,6 +1422,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-template-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz#1a0eb35d8bb3e6efc06c9fd40eb0bcef548328b8" + integrity sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-typeof-symbol@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" @@ -799,6 +1436,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-typeof-symbol@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz#70e966bb492e03509cf37eafa6dcc3051f844369" + integrity sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-unicode-escapes@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" @@ -806,6 +1450,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-unicode-escapes@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz#3e3143f8438aef842de28816ece58780190cf806" + integrity sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-property-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz#bdfe2d3170c78c5691a3c3be934c8c0087525956" + integrity sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-unicode-regex@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" @@ -814,6 +1473,98 @@ "@babel/helper-create-regexp-features-plugin" "^7.16.7" "@babel/helper-plugin-utils" "^7.16.7" +"@babel/plugin-transform-unicode-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz#25948f5c395db15f609028e370667ed8bae9af97" + integrity sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-sets-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz#6ab706d10f801b5c72da8bb2548561fa04193cd1" + integrity sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/preset-env@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.28.0.tgz#d23a6bc17b43227d11db77081a0779c706b5569c" + integrity sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg== + dependencies: + "@babel/compat-data" "^7.28.0" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.27.1" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.27.1" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.27.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.27.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.27.1" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-import-assertions" "^7.27.1" + "@babel/plugin-syntax-import-attributes" "^7.27.1" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.27.1" + "@babel/plugin-transform-async-generator-functions" "^7.28.0" + "@babel/plugin-transform-async-to-generator" "^7.27.1" + "@babel/plugin-transform-block-scoped-functions" "^7.27.1" + "@babel/plugin-transform-block-scoping" "^7.28.0" + "@babel/plugin-transform-class-properties" "^7.27.1" + "@babel/plugin-transform-class-static-block" "^7.27.1" + "@babel/plugin-transform-classes" "^7.28.0" + "@babel/plugin-transform-computed-properties" "^7.27.1" + "@babel/plugin-transform-destructuring" "^7.28.0" + "@babel/plugin-transform-dotall-regex" "^7.27.1" + "@babel/plugin-transform-duplicate-keys" "^7.27.1" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.27.1" + "@babel/plugin-transform-dynamic-import" "^7.27.1" + "@babel/plugin-transform-explicit-resource-management" "^7.28.0" + "@babel/plugin-transform-exponentiation-operator" "^7.27.1" + "@babel/plugin-transform-export-namespace-from" "^7.27.1" + "@babel/plugin-transform-for-of" "^7.27.1" + "@babel/plugin-transform-function-name" "^7.27.1" + "@babel/plugin-transform-json-strings" "^7.27.1" + "@babel/plugin-transform-literals" "^7.27.1" + "@babel/plugin-transform-logical-assignment-operators" "^7.27.1" + "@babel/plugin-transform-member-expression-literals" "^7.27.1" + "@babel/plugin-transform-modules-amd" "^7.27.1" + "@babel/plugin-transform-modules-commonjs" "^7.27.1" + "@babel/plugin-transform-modules-systemjs" "^7.27.1" + "@babel/plugin-transform-modules-umd" "^7.27.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.27.1" + "@babel/plugin-transform-new-target" "^7.27.1" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.27.1" + "@babel/plugin-transform-numeric-separator" "^7.27.1" + "@babel/plugin-transform-object-rest-spread" "^7.28.0" + "@babel/plugin-transform-object-super" "^7.27.1" + "@babel/plugin-transform-optional-catch-binding" "^7.27.1" + "@babel/plugin-transform-optional-chaining" "^7.27.1" + "@babel/plugin-transform-parameters" "^7.27.7" + "@babel/plugin-transform-private-methods" "^7.27.1" + "@babel/plugin-transform-private-property-in-object" "^7.27.1" + "@babel/plugin-transform-property-literals" "^7.27.1" + "@babel/plugin-transform-regenerator" "^7.28.0" + "@babel/plugin-transform-regexp-modifiers" "^7.27.1" + "@babel/plugin-transform-reserved-words" "^7.27.1" + "@babel/plugin-transform-shorthand-properties" "^7.27.1" + "@babel/plugin-transform-spread" "^7.27.1" + "@babel/plugin-transform-sticky-regex" "^7.27.1" + "@babel/plugin-transform-template-literals" "^7.27.1" + "@babel/plugin-transform-typeof-symbol" "^7.27.1" + "@babel/plugin-transform-unicode-escapes" "^7.27.1" + "@babel/plugin-transform-unicode-property-regex" "^7.27.1" + "@babel/plugin-transform-unicode-regex" "^7.27.1" + "@babel/plugin-transform-unicode-sets-regex" "^7.27.1" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.14" + babel-plugin-polyfill-corejs3 "^0.13.0" + babel-plugin-polyfill-regenerator "^0.6.5" + core-js-compat "^3.43.0" + semver "^6.3.1" + "@babel/preset-env@^7.9.0": version "7.16.11" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" @@ -894,6 +1645,15 @@ core-js-compat "^3.20.2" semver "^6.3.0" +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + "@babel/preset-modules@^0.1.5": version "0.1.5" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" @@ -905,17 +1665,17 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.14.5": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" - integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== +"@babel/preset-react@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.27.1.tgz#86ea0a5ca3984663f744be2fd26cb6747c3fd0ec" + integrity sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-react-display-name" "^7.16.7" - "@babel/plugin-transform-react-jsx" "^7.16.7" - "@babel/plugin-transform-react-jsx-development" "^7.16.7" - "@babel/plugin-transform-react-pure-annotations" "^7.16.7" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-transform-react-display-name" "^7.27.1" + "@babel/plugin-transform-react-jsx" "^7.27.1" + "@babel/plugin-transform-react-jsx-development" "^7.27.1" + "@babel/plugin-transform-react-pure-annotations" "^7.27.1" "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.17.9" @@ -933,6 +1693,15 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" +"@babel/template@^7.27.1", "@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9": version "7.17.9" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d" @@ -949,6 +1718,19 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.27.1", "@babel/traverse@^7.27.3", "@babel/traverse@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.0.tgz#518aa113359b062042379e333db18380b537e34b" + integrity sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.0" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.0" + debug "^4.3.1" + "@babel/types@7.0.0-beta.35": version "7.0.0-beta.35" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.35.tgz#cf933a9a9a38484ca724b335b88d83726d5ab960" @@ -966,6 +1748,14 @@ "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.0", "@babel/types@^7.28.2": + version "7.28.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b" + integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@develar/schema-utils@~2.6.5": version "2.6.5" resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz#3ece22c5838402419a6e0425f85742b961d9b6c6" @@ -1090,16 +1880,34 @@ resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.12" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz#2234ce26c62889f03db3d7fea43c1932ab3e927b" + integrity sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.11" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" + integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== + "@jridgewell/trace-mapping@^0.3.0": version "0.3.4" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" @@ -1108,6 +1916,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.29" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" + integrity sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -1843,6 +2659,23 @@ babel-plugin-polyfill-corejs2@^0.3.0: "@babel/helper-define-polyfill-provider" "^0.3.1" semver "^6.1.1" +babel-plugin-polyfill-corejs2@^0.4.14: + version "0.4.14" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz#8101b82b769c568835611542488d463395c2ef8f" + integrity sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg== + dependencies: + "@babel/compat-data" "^7.27.7" + "@babel/helper-define-polyfill-provider" "^0.6.5" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz#bb7f6aeef7addff17f7602a08a6d19a128c30164" + integrity sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.5" + core-js-compat "^3.43.0" + babel-plugin-polyfill-corejs3@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" @@ -1858,6 +2691,13 @@ babel-plugin-polyfill-regenerator@^0.3.0: dependencies: "@babel/helper-define-polyfill-provider" "^0.3.1" +babel-plugin-polyfill-regenerator@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz#32752e38ab6f6767b92650347bf26a31b16ae8c5" + integrity sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.5" + babel-plugin-syntax-jsx@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" @@ -2110,6 +2950,16 @@ browserslist@^4.17.5, browserslist@^4.19.1: node-releases "^2.0.2" picocolors "^1.0.0" +browserslist@^4.24.0, browserslist@^4.25.1: + version "4.25.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" + integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== + dependencies: + caniuse-lite "^1.0.30001726" + electron-to-chromium "^1.5.173" + node-releases "^2.0.19" + update-browserslist-db "^1.1.3" + buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -2349,6 +3199,11 @@ caniuse-lite@^1.0.30001317: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001331.tgz#41048f2a5cf0c3c6198f40207cd323388b3d4399" integrity sha512-Y1xk6paHpUXKP/P6YjQv1xqyTbgAP05ycHBcRdQjTcyXlWol868sJJPlmk5ylOekw2BrucWes5jk+LvVd7WZ5Q== +caniuse-lite@^1.0.30001726: + version "1.0.30001731" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz#277c07416ea4613ec564e5b0ffb47e7b60f32e2f" + integrity sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -2702,6 +3557,11 @@ convert-source-map@^1.5.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -2737,6 +3597,13 @@ core-js-compat@^3.20.2, core-js-compat@^3.21.0: browserslist "^4.19.1" semver "7.0.0" +core-js-compat@^3.43.0: + version "3.44.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.44.0.tgz#62b9165b97e4cbdb8bca16b14818e67428b4a0f8" + integrity sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA== + dependencies: + browserslist "^4.25.1" + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2942,6 +3809,13 @@ debug@^3.1.1, debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3346,6 +4220,11 @@ electron-to-chromium@^1.4.84: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.107.tgz#564257014ab14033b4403a309c813123c58a3fb9" integrity sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg== +electron-to-chromium@^1.5.173: + version "1.5.194" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz#05e541c3373ba8d967a65c92bc14d60608908236" + integrity sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA== + electron-webpack-js@~2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/electron-webpack-js/-/electron-webpack-js-2.4.1.tgz#5389cc22f34c71f6416d5ba1e043f9b0fd6130af" @@ -3531,6 +4410,11 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-goat@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" @@ -4014,6 +4898,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + gauge@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" @@ -4333,6 +5222,13 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -4779,6 +5675,13 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + is-core-module@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" @@ -5109,11 +6012,21 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= +jsesc@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" @@ -5156,6 +6069,11 @@ json5@^2.1.0, json5@^2.1.2, json5@^2.2.0, json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -5654,7 +6572,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5782,6 +6700,11 @@ node-loader@^0.6.0: resolved "https://registry.yarnpkg.com/node-loader/-/node-loader-0.6.0.tgz#c797ef51095ed5859902b157f6384f6361e05ae8" integrity sha1-x5fvUQle1YWZArFX9jhPY2HgWug= +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + node-releases@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.3.tgz#225ee7488e4a5e636da8da52854844f9d716ca96" @@ -6230,6 +7153,11 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -6775,6 +7703,13 @@ regenerate-unicode-properties@^10.0.1: dependencies: regenerate "^1.4.2" +regenerate-unicode-properties@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" + integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== + dependencies: + regenerate "^1.4.2" + regenerate@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" @@ -6820,6 +7755,18 @@ regexpu-core@^5.0.1: unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.0.0" +regexpu-core@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.2.0.tgz#0e5190d79e542bf294955dccabae04d3c7d53826" + integrity sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.2.0" + regjsgen "^0.8.0" + regjsparser "^0.12.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + registry-auth-token@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" @@ -6839,6 +7786,18 @@ regjsgen@^0.6.0: resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.12.0.tgz#0e846df6c6530586429377de56e0475583b088dc" + integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ== + dependencies: + jsesc "~3.0.2" + regjsparser@^0.8.2: version "0.8.4" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" @@ -6957,6 +7916,15 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.10: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -7123,6 +8091,11 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" @@ -8004,6 +8977,11 @@ unicode-match-property-value-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== +unicode-match-property-value-ecmascript@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz#a0401aee72714598f739b68b104e4fe3a0cb3c71" + integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== + unicode-property-aliases-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" @@ -8068,6 +9046,14 @@ upath@^1.1.1: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + update-notifier@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9"