diff options
| author | Ken Chen <[email protected]> | 2021-05-28 17:54:41 +1000 |
|---|---|---|
| committer | Ken Chen <[email protected]> | 2021-05-28 17:54:41 +1000 |
| commit | 2ca85a2bcdbf5e4b3938b95754d06b96de382bd9 (patch) | |
| tree | 6864859bf5e26cf5e700c386e40899d1d48ee740 /src/lib | |
| parent | efcf6e9bf010502f831dad0be5e01651c928281b (diff) | |
| download | librazermacos-2ca85a2bcdbf5e4b3938b95754d06b96de382bd9.tar.xz librazermacos-2ca85a2bcdbf5e4b3938b95754d06b96de382bd9.zip | |
basic C cli frontend
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/razeraccessory_driver.c | 518 | ||||
| -rw-r--r-- | src/lib/razerchromacommon.c | 1242 | ||||
| -rw-r--r-- | src/lib/razercommon.c | 171 | ||||
| -rwxr-xr-x | src/lib/razerdevice.c | 470 | ||||
| -rw-r--r-- | src/lib/razeregpu_driver.c | 281 | ||||
| -rwxr-xr-x | src/lib/razerheadphone_driver.c | 223 | ||||
| -rw-r--r-- | src/lib/razerkbd_driver.c | 1560 | ||||
| -rw-r--r-- | src/lib/razerkraken_driver.c | 324 | ||||
| -rw-r--r-- | src/lib/razermouse_driver.c | 2210 | ||||
| -rw-r--r-- | src/lib/razermousedock_driver.c | 242 | ||||
| -rw-r--r-- | src/lib/razermousemat_driver.c | 333 |
11 files changed, 7574 insertions, 0 deletions
diff --git a/src/lib/razeraccessory_driver.c b/src/lib/razeraccessory_driver.c new file mode 100644 index 0000000..7a429a5 --- /dev/null +++ b/src/lib/razeraccessory_driver.c @@ -0,0 +1,518 @@ +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to Terry Cain <[email protected]> + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "razeraccessory_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/** + * Send report to the device + */ +static int razer_get_report(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report, struct razer_report *response_report) +{ + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_ACCESSORY_WAIT_MIN_US); +} + +/** + * Function to send to device, get response, and actually check the response + */ +static struct razer_report razer_send_payload(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report) +{ + int retval = -1; + struct razer_report response_report = {0}; + + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(usb_dev, request_report, &response_report); + + 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 (accessory)\n"); + } else if (response_report.status == RAZER_CMD_BUSY) { + //printf("Device is busy (accessory)\n"); + } else if (response_report.status == RAZER_CMD_FAILURE) { + printf("Command failed (accessory)\n"); + } else if (response_report.status == RAZER_CMD_NOT_SUPPORTED) { + printf("Command not supported (accessory)\n"); + } else if (response_report.status == RAZER_CMD_TIMEOUT) { + printf("Command timed out (accessory)\n"); + } + } else { + printf("Invalid Report Length (accessory)\n"); + } + + return response_report; +} + +/** + * Write device file "mode_spectrum" + * + * Specrum effect mode is activated whenever the file is written to + */ +ssize_t razer_accessory_attr_write_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = { 0 }; + + switch (product) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + report = razer_chroma_standard_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x3F; + 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: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x1F; + break; + + default: + printf("razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_none" + * + * None effect mode is activated whenever the file is written to + */ +ssize_t razer_accessory_attr_write_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = { 0 }; + + switch (product) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + report = razer_chroma_standard_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x3F; + 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: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x1F; + break; + + default: + printf("razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_blinking" + * + * Blinking effect mode is activated whenever the file is written to with 3 bytes + */ +ssize_t razer_accessory_attr_write_mode_blinking(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + + struct razer_report report_rgb = {0}; + struct razer_report report_effect = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, 0x01); + report_effect.transaction_id.id = 0x3F; + + if(count == 3) { + report_rgb = razer_chroma_standard_set_led_rgb(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + report_rgb.transaction_id.id = 0x3F; + + razer_send_payload(usb_dev, &report_rgb); + usleep(5 * 1000); + razer_send_payload(usb_dev, &report_effect); + + } else { + printf("razeraccessory: Blinking mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "mode_custom" + * + * Sets the device to custom mode whenever the file is written to + */ +ssize_t razer_accessory_attr_write_mode_custom(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = { 0 }; + + switch (product) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + report = razer_chroma_standard_matrix_effect_custom_frame(NOSTORE); + 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: + report = razer_chroma_extended_matrix_effect_custom_frame(); + break; + + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report = razer_chroma_extended_matrix_effect_custom_frame(); + report.transaction_id.id = 0x1F; + break; + + default: + printf("razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_static" + * + * Static effect mode is activated whenever the file is written to with 3 bytes + */ +ssize_t razer_accessory_attr_write_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = {0}; + + if(count == 3) { + switch (product) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + report = razer_chroma_standard_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*) & buf[0]); + report.transaction_id.id = 0x3F; + 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: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + report.transaction_id.id = 0x1F; + break; + + default: + printf("razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + } else { + printf("razeraccessory: Static mode only accepts RGB (3byte)\n"); + } + + 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 + */ +ssize_t razer_accessory_attr_write_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int speed) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + unsigned char direction = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = { 0 }; + + switch (product) { + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + report = razer_chroma_standard_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + report.transaction_id.id = 0x3F; + 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: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction, speed); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction, speed); + report.transaction_id.id = 0x1F; + break; + + default: + printf("razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_breath" + * + * Breathing effect mode is activated whenever the file is written to with 1, 3, or 6 bytes + */ +ssize_t razer_accessory_attr_write_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = {0}; + + switch (product) { + 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: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x3F; + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + report.transaction_id.id = 0x3F; + break; + + default: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x3F; + break; + } + break; + + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x1F; + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + report.transaction_id.id = 0x1F; + break; + + default: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x1F; + break; + } + break; + + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_standard_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x3F; + break; + + case 6: // Dual colour mode + report = razer_chroma_standard_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + report.transaction_id.id = 0x3F; + break; + + default: // "Random" colour mode + report = razer_chroma_standard_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x3F; + break; + } + break; + + default: + printf("razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "device_mode" + */ +ssize_t razer_accessory_attr_write_device_mode(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = {0}; + + if (count != 2) { + printf("razeraccessory: Device mode only takes 2 bytes."); + } else { + + report = razer_chroma_standard_set_device_mode(buf[0], buf[1]); + + switch(product) { + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report.transaction_id.id = 0x1F; + break; + } + + razer_send_payload(usb_dev, &report); + } + + return count; +} + +ssize_t razer_accessory_attr_read_get_cup_state(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = get_razer_report(0x02, 0x81, 0x02); + struct razer_report response = {0}; + + response = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "%u\n", response.arguments[1]); +} + +/** + * Read device file "device_mode" + * + * Returns a string + */ +ssize_t razer_accessory_attr_read_device_mode(IOUSBDeviceInterface **usb_dev, char *buf) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = razer_chroma_standard_get_device_mode(); + struct razer_report response = {0}; + + switch(product) { + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report.transaction_id.id = 0x1F; + break; + } + + response = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "%d:%d\n", response.arguments[0], response.arguments[1]); +} + +/** + * Write device file "set_brightness" + * + * Sets the brightness to the ASCII number written to this file. + */ +ssize_t razer_accessory_attr_write_set_brightness(IOUSBDeviceInterface **usb_dev, ushort brightness, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = {0}; + + switch (product) { + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + report = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_CHROMA_MUG: + report = razer_chroma_standard_set_led_brightness(VARSTORE, BACKLIGHT_LED, brightness); + 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: + report = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + break; + + default: + printf("razeraccessory: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Read device file "set_brightness" + * + * Returns brightness or -1 if the initial brightness is not known + */ +ushort razer_accessory_attr_read_set_brightness(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + struct razer_report response = {0}; + unsigned char brightness = 0; + + switch (product) { + case USB_DEVICE_ID_RAZER_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + break; + + default: + response = razer_send_payload(usb_dev, &report); + brightness = response.arguments[2]; + break; + } + + return brightness; +}
\ No newline at end of file diff --git a/src/lib/razerchromacommon.c b/src/lib/razerchromacommon.c new file mode 100644 index 0000000..6f6410e --- /dev/null +++ b/src/lib/razerchromacommon.c @@ -0,0 +1,1242 @@ +#include <math.h> + +#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; + } + if(param != 0x00) { + 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, ushort brightness) +{ + struct razer_report report = get_razer_report(0x03, 0x03, 0x03); + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = round(brightness * 2.55); //Razer macOS special: brightness is coming [0-100], matrix brightness range is from [0-255] though + + 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 + */ + +// TODO remove varstore and led_id +/** + * 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(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x01); + report.arguments[0] = 0x00; // Effect ID + + return report; +} + +/** + * 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 variable_storage, unsigned char led_id, unsigned char wave_direction) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x02); + report.arguments[0] = 0x01; // Effect ID + 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(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x01); + report.arguments[0] = 0x04; // Effect ID + + return report; +} + +/** + * 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 variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x05); + report.arguments[0] = 0x02; // Effect ID + 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(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x04); + report.arguments[0] = 0x06; // Effect ID + 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 variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x01); + + speed = clamp_u8(0x01, 0x01, 0x03); // For now only seen + + report.arguments[0] = 0x19; // Effect ID + report.arguments[1] = 0x01; // Type one color + report.arguments[2] = speed; // 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 variable_storage, unsigned char led_id, unsigned char speed, struct razer_rgb *rgb1, struct razer_rgb *rgb2) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x01); + + speed = clamp_u8(speed, 0x01, 0x03); // For now only seen + + report.arguments[0] = 0x19; // Effect ID + report.arguments[1] = 0x02; // Type two color + report.arguments[2] = speed; // 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 variable_storage, unsigned char led_id, unsigned char speed) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x01); + + speed = clamp_u8(speed, 0x01, 0x03); // For now only seen + + report.arguments[0] = 0x19; // Effect ID + report.arguments[1] = 0x03; // Type random color + report.arguments[2] = speed; // 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(unsigned char variable_storage, unsigned char led_id) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x08); + report.arguments[0] = 0x03; // Effect ID + report.arguments[1] = 0x03; // Breathing type + + return report; +} +struct razer_report razer_chroma_standard_matrix_effect_breathing_single(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x08); + report.arguments[0] = 0x03; // Effect ID + 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(unsigned char variable_storage, unsigned char led_id, struct razer_rgb *rgb1, struct razer_rgb *rgb2) +{ + struct razer_report report = get_razer_report(0x03, 0x0A, 0x08); + report.arguments[0] = 0x03; // Effect ID + 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 = get_razer_report(0x03, 0x0A, 0x02); + report.arguments[0] = 0x05; // Effect ID + report.arguments[1] = variable_storage; // Data frame ID + // report.arguments[1] = 0x01; // 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) +{ + size_t row_length = (size_t) (((stop_col + 1) - start_col) * 3); + struct razer_report 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 + */ +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.transaction_id.id = 0x3F; + + 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, int speed) +{ + 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); + + report.arguments[3] = direction; + report.arguments[4] = speed; // Speed, lower values are faster (). The default used to be 0x28 + 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 "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.transaction_id.id = 0x3F; + + report.arguments[0] = variable_storage; + report.arguments[1] = led_id; + report.arguments[2] = round(brightness * 2.55); //Razer macOS special: brightness is coming [0-100], matrix brightness range is from [0-255] though + + 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.transaction_id.id = 0x3F; + + 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 row_length = (size_t) (((stop_col + 1) - start_col) * 3); + // 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 + const size_t data_length = (packetLength != 0) ? packetLength : row_length + 5; + struct razer_report report = get_razer_report(0x0F, 0x03, data_length); + + report.transaction_id.id = 0x3F; + + // 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 + */ +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.transaction_id.id = 0x3F; + + 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 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 +{ + struct razer_report report = get_razer_report(0x03, 0x0C, 0x32); + size_t row_length = (size_t) (((stop_col + 1) - start_col) * 3); + + 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 = get_razer_report(0x03, 0x0A, 0x05); + report.arguments[0] = 0x02; // Effect ID + 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 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, 128, 20000); + dpi_y = clamp_u16(dpi_y, 128, 20000); + + 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] = VARSTORE; + + 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 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; +} + +/** + * 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 idle time 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)); + + // Keep the idle time within bounds + 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; + report.transaction_id.id = 0x1f; + + return report; +} + + + + + + + + + + + + + + + + diff --git a/src/lib/razercommon.c b/src/lib/razercommon.c new file mode 100644 index 0000000..4c8424a --- /dev/null +++ b/src/lib/razercommon.c @@ -0,0 +1,171 @@ +// +// razercommon.c +// RazerBlade +// +// Based on Linux razer-driver kernel drivers: https://github.com/terrycain/razer-drivers/blob/master/driver/razercommon.h +// +#include <stdio.h> +#include <string.h> + +#include "razercommon.h" + +/** + * Send USB control report to the keyboard + * USUALLY index = 0x02 + * FIREFLY is 0 + */ +IOReturn razer_send_control_msg(IOUSBDeviceInterface **dev, void const *data, uint report_index) { + IOUSBDevRequest request; + + request.bRequest = HID_REQ_SET_REPORT; // 0x09 + request.bmRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT; + request.wValue = 0x300; + request.wIndex = report_index; + request.wLength = RAZER_USB_REPORT_LEN; + request.pData = (void*)data; + + return (*dev)->DeviceRequest(dev, &request); +} + + +/** + * 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 specifing what response we want + * Response report will get populated with a response + * + * Returns kIOReturnSuccess when successful + */ +IOReturn razer_get_usb_response(IOUSBDeviceInterface **dev, uint report_index, struct razer_report* request_report, uint response_index, struct razer_report* response_report, int wait_us) { + IOReturn retval; + char buffer[sizeof(struct razer_report)]; + + // 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(dev, request_report, report_index); + + if(retval != kIOReturnSuccess) { + printf("razer_send_control_msg failed!\n"); + + return retval; + } + + usleep(wait_us); + + IOUSBDevRequest request; + + request.bRequest = HID_REQ_GET_REPORT; + request.bmRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN; + request.wValue = 0x300; + request.wIndex = report_index; + request.wLength = RAZER_USB_REPORT_LEN; + request.pData = buffer; + + retval = (*dev)->DeviceRequest(dev, &request); + + if(retval != kIOReturnSuccess) { + printf("razer_get_usb_response failed\n"); + + return retval; + } + + memcpy(response_report, buffer, sizeof(struct razer_report)); + + + return retval; +} + + +/** + * 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 = get_empty_razer_report(); + + new_report.status = 0x00; + new_report.transaction_id.id = 0xFF; + 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; +} + + +/** + * 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; +} + + +/** + * 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; +} + +IOReturn razer_send_control_msg_old_device(IOUSBDeviceInterface **dev, void const *data, uint report_value, uint report_index, uint report_size) +{ + IOUSBDevRequest request; + + request.bRequest = HID_REQ_SET_REPORT; // 0x09 + request.bmRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT; // 0x21 + request.wValue = report_value; + request.wIndex = report_index; + request.wLength = report_size; + request.pData = (void*)data; + + return (*dev)->DeviceRequest(dev, &request); +} diff --git a/src/lib/razerdevice.c b/src/lib/razerdevice.c new file mode 100755 index 0000000..2b1bda7 --- /dev/null +++ b/src/lib/razerdevice.c @@ -0,0 +1,470 @@ +#include <stdlib.h> +#include "razerdevice.h" + +bool is_razer_device(IOUSBDeviceInterface **dev) +{ + kern_return_t kr; + UInt16 vendor; + UInt16 product; + UInt16 release; + + kr = (*dev)->GetDeviceVendor(dev, &vendor); + kr = (*dev)->GetDeviceProduct(dev, &product); + kr = (*dev)->GetDeviceReleaseNumber(dev, &release); + + return vendor == USB_VENDOR_ID_RAZER; +} + +bool is_keyboard(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_NOSTROMO: + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + 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_ULTIMATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_OVERWATCH: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + 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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_2019: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ESSENTIAL: + case USB_DEVICE_ID_RAZER_ORNATA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + case USB_DEVICE_ID_RAZER_HUNTSMAN_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_HUNTSMAN: + case USB_DEVICE_ID_RAZER_CYNOSA_CHROMA: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + 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_HUNTSMAN_MINI: + return true; + } + + return false; +} + +bool is_mouse(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_OROCHI_2011: + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + 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_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_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_ABYSSUS_2000: + case USB_DEVICE_ID_RAZER_LANCEHEAD_TE_WIRED: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + 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_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_VIPER: + case USB_DEVICE_ID_RAZER_VIPER_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + 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_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + return true; + } + + return false; +} + +bool is_mouse_dock(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_MOUSE_CHARGING_DOCK: + return true; + } + + return false; +} + +bool is_mouse_mat(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_FIREFLY: + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + return true; + } + + return false; +} + +bool is_egpu(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + return true; + } + + return false; +} + + +bool is_headphone(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + return true; + } + + return false; +} + +bool is_accessory(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_NOMMO_CHROMA: + case USB_DEVICE_ID_RAZER_NOMMO_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_MOUSE_BUNGEE_V3_CHROMA: + case USB_DEVICE_ID_RAZER_BASE_STATION_V2_CHROMA: + return true; + } + + return false; +} + +IOUSBDeviceInterface **getRazerUSBDeviceInterface(int type) +{ + CFMutableDictionaryRef matchingDict; + matchingDict = IOServiceMatching(kIOUSBDeviceClassName); + if (matchingDict == NULL) + { + return NULL; + } + + io_iterator_t iter; + kern_return_t kReturn = + IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter); + if (kReturn != kIOReturnSuccess) + { + return NULL; + } + + io_service_t usbDevice; + while ((usbDevice = IOIteratorNext(iter))) + { + IOCFPlugInInterface **plugInInterface = NULL; + SInt32 score; + + kReturn = IOCreatePlugInInterfaceForService( + usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); + + IOObjectRelease(usbDevice); // Not needed after plugin created + if ((kReturn != kIOReturnSuccess) || plugInInterface == NULL) + { + // printf("Unable to create plugin (0x%08x)\n", kReturn); + continue; + } + + IOUSBDeviceInterface **dev = NULL; + HRESULT hResult = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID *)&dev); + + (*plugInInterface)->Release(plugInInterface); // Not needed after device interface created + if (hResult || !dev) + { + // printf("Couldn’t create a device interface (0x%08x)\n", (int) hResult); + continue; + } + + // Filter out non-Razer devices + if (!is_razer_device(dev)) + { + (*dev)->Release(dev); + continue; + } + + switch (type) + { + case TYPE_KEYBOARD: + case TYPE_BLADE: + // Filter out non-keyboards and non-blade laptops + if (!(is_keyboard(dev) || is_blade_laptop(dev))) + { + (*dev)->Release(dev); + continue; + } + break; + + case TYPE_MOUSE: + // Filter out non-mice + if (!is_mouse(dev)) + { + (*dev)->Release(dev); + continue; + } + break; + + case TYPE_MOUSE_DOCK: + // Filter out non-mice-mats + if (!is_mouse_dock(dev)) + { + (*dev)->Release(dev); + continue; + } + break; + + case TYPE_MOUSE_MAT: + // Filter out non-mice-mats + if (!is_mouse_mat(dev)) + { + (*dev)->Release(dev); + continue; + } + break; + + case TYPE_HEADPHONE: + if (!is_headphone(dev)) + { + (*dev)->Release(dev); + continue; + } + break; + + case TYPE_EGPU: + // Filter out non-mice-mats + if (!is_egpu(dev)) + { + (*dev)->Release(dev); + continue; + } + break; + case TYPE_ACCESSORY: + if (!is_accessory(dev)) + { + (*dev)->Release(dev); + continue; + } + break; + + default: + // Unsupported Razer peripheral type + (*dev)->Release(dev); + continue; + } + + kReturn = (*dev)->USBDeviceOpen(dev); + if (kReturn != kIOReturnSuccess) + { + printf("Unable to open USB device: %08x\n", kReturn); + (*dev)->Release(dev); + continue; + } + + // Success. We found the Razer USB device. + // Caller is responsible for closing USB and release device. + IOObjectRelease(iter); + return dev; + } + + IOObjectRelease(iter); + return NULL; +} + +void closeRazerUSBDeviceInterface(IOUSBDeviceInterface **dev) +{ + kern_return_t kr; + kr = (*dev)->USBDeviceClose(dev); + kr = (*dev)->Release(dev); +} + +RazerDevices getAllRazerDevices() +{ + RazerDevices allDevices = { .devices = NULL, .size = 0 }; + + CFMutableDictionaryRef matchingDict; + matchingDict = IOServiceMatching(kIOUSBDeviceClassName); + if (matchingDict == NULL) + { + return allDevices; + } + + io_iterator_t iter; + kern_return_t kReturn = + IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter); + if (kReturn != kIOReturnSuccess) + { + return allDevices; + } + + int array_size = 0; + int array_index = -1; + RazerDevice *razerDevices = malloc(array_size * sizeof(RazerDevice)); + + io_service_t usbDevice; + while ((usbDevice = IOIteratorNext(iter))) + { + IOCFPlugInInterface **plugInInterface = NULL; + SInt32 score; + + kReturn = IOCreatePlugInInterfaceForService( + usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); + + IOObjectRelease(usbDevice); // Not needed after plugin created + if ((kReturn != kIOReturnSuccess) || plugInInterface == NULL) + { + // printf("Unable to create plugin (0x%08x)\n", kReturn); + continue; + } + + IOUSBDeviceInterface **dev = NULL; + HRESULT hResult = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID *)&dev); + + (*plugInInterface)->Release(plugInInterface); // Not needed after device interface created + if (hResult || !dev) + { + // printf("Couldn’t create a device interface (0x%08x)\n", (int) hResult); + continue; + } + + // Filter out non-Razer devices + if (!is_razer_device(dev)) + { + (*dev)->Release(dev); + continue; + } + + if(!is_keyboard(dev) + && !is_blade_laptop(dev) + && !is_mouse(dev) + && !is_mouse_dock(dev) + && !is_mouse_dock(dev) + && !is_mouse_mat(dev) + && !is_headphone(dev) + && !is_egpu(dev) + && !is_accessory(dev) + ) { + (*dev)->Release(dev); + continue; + } + + kReturn = (*dev)->USBDeviceOpen(dev); + if (kReturn != kIOReturnSuccess) + { + printf("Unable to open USB device: %08x\n", kReturn); + (*dev)->Release(dev); + continue; + } + + // Success. We found the Razer USB device. + // Caller is responsible for closing USB and release device. + array_size++; + razerDevices = realloc(razerDevices, array_size * sizeof(RazerDevice)); + array_index++; + + UInt16 productId; + (*dev)->GetDeviceProduct(dev, &productId); + + RazerDevice newDevice = { .usbDevice = dev, .internalDeviceId = array_index, .productId = productId }; + razerDevices[array_index] = newDevice; + } + + IOObjectRelease(iter); + allDevices.devices = razerDevices; + allDevices.size = array_size; + return allDevices; +} + +void closeAllRazerDevices(RazerDevices devices) +{ + for(int counter=0; counter < devices.size; ++counter) { + IOUSBDeviceInterface **dev = devices.devices[counter].usbDevice; + (*dev)->USBDeviceClose(dev); + (*dev)->Release(dev); + } + free(devices.devices); + devices.devices = NULL; +} diff --git a/src/lib/razeregpu_driver.c b/src/lib/razeregpu_driver.c new file mode 100644 index 0000000..8965c97 --- /dev/null +++ b/src/lib/razeregpu_driver.c @@ -0,0 +1,281 @@ +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to Terry Cain <[email protected]> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "razeregpu_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/** + * Send report to the mouse mat + */ +static int razer_get_report(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report, struct razer_report *response_report) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_EGPU_WAIT_MIN_US); +} + +/** + * Function to send to device, get response, and actually check the response + */ +static struct razer_report razer_send_payload(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report) +{ + IOReturn retval = -1; + + struct razer_report response_report = {0}; + + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(usb_dev, request_report, &response_report); + + 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 (egpu)\n"); + } else if (response_report.status == RAZER_CMD_BUSY) { + //printf("Device is busy (egpu)\n"); + } else if (response_report.status == RAZER_CMD_FAILURE) { + printf("Command failed (egpu)\n"); + } else if (response_report.status == RAZER_CMD_NOT_SUPPORTED) { + printf("Command not supported (egpu)\n"); + } else if (response_report.status == RAZER_CMD_TIMEOUT) { + printf("Command timed out (egpu)\n"); + } + } else { + printf("Invalid Report Length (egpu)\n"); + } + + return response_report; +} + +/** + * Write device file "mode_none" + * + * No effect is activated whenever this file is written to + */ +ssize_t razer_egpu_attr_write_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + break; + + default: + report = razer_chroma_standard_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + break; + } + + razer_send_payload(usb_dev, &report); + + 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 + */ +ssize_t razer_egpu_attr_write_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + unsigned char direction = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction, 0x28); + break; + + default: + report = razer_chroma_standard_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + break; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "mode_breath" + */ +ssize_t razer_egpu_attr_write_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + switch (count) + { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + case 6: // Dual colour mode + report = 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 + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + break; + } + break; + + default: + switch (count) + { + case 3: // Single colour mode + report = razer_chroma_standard_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_standard_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_standard_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + break; + } + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_static" + * + * Set the mousemat to static mode when 3 RGB bytes are written + */ +ssize_t razer_egpu_attr_write_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if (count == 3) + { + switch (product) + { + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + default: + report = razer_chroma_standard_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + break; + } + + razer_send_payload(usb_dev, &report); + } + else + { + printf("razermousemat: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "mode_static" + * + * ** NOSTORE version for efficiency in custom lighting configurations + * + * Set the mousemat to static mode when 3 RGB bytes are written + */ +ssize_t razer_egpu_attr_write_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if (count == 3) + { + switch (product) + { + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + default: + report = razer_chroma_standard_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + break; + } + + razer_send_payload(usb_dev, &report); + } + else + { + printf("razermousemat: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "mode_spectrum" + * + * Specrum effect mode is activated whenever the file is written to + */ +ssize_t razer_egpu_attr_write_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_CORE_X_CHROMA: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + break; + + default: + report = razer_chroma_standard_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + break; + } + + razer_send_payload(usb_dev, &report); + return count; +}
\ No newline at end of file diff --git a/src/lib/razerheadphone_driver.c b/src/lib/razerheadphone_driver.c new file mode 100755 index 0000000..a09316e --- /dev/null +++ b/src/lib/razerheadphone_driver.c @@ -0,0 +1,223 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "razerheadphone_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" +#include "razerkraken_driver.h" + +/** + * Send report to the headphone + */ +static int razer_get_report(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report, struct razer_report *response_report) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_HEADPHONE_WAIT_MIN_US); +} + +/** + * Function to send to device, get response, and actually check the response + */ +static struct razer_report razer_send_payload(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report) +{ + IOReturn retval = -1; + + struct razer_report response_report = {0}; + + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(usb_dev, request_report, &response_report); + + 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 (headphone)\n"); + } else if (response_report.status == RAZER_CMD_FAILURE) { + printf("Command failed (headphone)\n"); + } else if (response_report.status == RAZER_CMD_NOT_SUPPORTED) { + printf("Command not supported (headphone)\n"); + } else if (response_report.status == RAZER_CMD_TIMEOUT) { + printf("Command timed out (headphone)\n"); + } + } else { + printf("Invalid Report Length (headphone)\n"); + } + + return response_report; +} + +/** + * Write device file "mode_none" + * + * No effect is activated whenever this file is written to + */ +ssize_t razer_headphone_attr_write_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x1F; + break; + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + return razer_kraken_attr_write_mode_none(usb_dev, buf, count); + default: + report = razer_chroma_standard_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_breath" + */ +ssize_t razer_headphone_attr_write_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x1F; + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + report.transaction_id.id = 0x1F; + break; + + default: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x1F; + break; + } + break; + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + // "Random" colour mode + if(count == 1) { + count = 3; + char color[3] = {(unsigned char)rand(), (unsigned char)rand(), (unsigned char)rand()}; + return razer_kraken_attr_write_mode_breath(usb_dev, color, count); + } + return razer_kraken_attr_write_mode_breath(usb_dev, buf, count); + default: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_standard_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_standard_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_standard_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + break; + } + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_static" + * + * Set the headphone to static mode when 3 RGB bytes are written + */ +ssize_t razer_headphone_attr_write_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x1F; + break; + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + return razer_kraken_attr_write_mode_static(usb_dev, buf, count); + default: + report = razer_chroma_standard_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + break; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razerheadphone: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "mode_static" + * + * ** NOSTORE version for efficiency in custom lighting configurations + * + * Set the headphone to static mode when 3 RGB bytes are written + */ +ssize_t razer_headphone_attr_write_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_KRAKEN_KITTY_EDITION: + case USB_DEVICE_ID_RAZER_KRAKEN_ULTIMATE: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x1F; + break; + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + return razer_kraken_attr_write_mode_static(usb_dev, buf, count); + default: + report = razer_chroma_standard_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + break; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razerheadphone: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +ssize_t razer_headphone_attr_write_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + switch(product) { + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + return razer_kraken_attr_write_mode_spectrum(usb_dev, buf, count); + } + return count; +}
\ No newline at end of file diff --git a/src/lib/razerkbd_driver.c b/src/lib/razerkbd_driver.c new file mode 100644 index 0000000..054e8af --- /dev/null +++ b/src/lib/razerkbd_driver.c @@ -0,0 +1,1560 @@ +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to Terry Cain <[email protected]> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "razerkbd_driver.h" +#include "razerchromacommon.h" +#include "razercommon.h" + +static struct razer_report razer_send_payload(IOUSBDeviceInterface **dev, struct razer_report *request_report); + +bool is_blade_laptop(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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: + return true; + } + + return false; +} + +/** + * Read device file "game_mode" + * + * Returns a string + */ +ssize_t razer_attr_read_mode_game(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_standard_get_led_state(VARSTORE, GAME_LED); + struct razer_report response; + + response = razer_send_payload(usb_dev, &report); + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Write device file "mode_macro" + * + * When 1 is written (as a character, 0x31) Macro mode will be enabled, if 0 is written (0x30) + * then game mode will be disabled + */ +ssize_t razer_attr_write_mode_macro(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + unsigned char enabled = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = razer_chroma_standard_set_led_state(VARSTORE, MACRO_LED, enabled); + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_macro_effect" + * + * When 1 is written the LED will blink, 0 will static + */ +ssize_t razer_attr_write_mode_macro_effect(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + + struct razer_report report = {0}; + unsigned char enabled = (unsigned char)strtoul(buf, NULL, 10); + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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_CHROMA_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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_standard_set_led_effect(NOSTORE, MACRO_LED, enabled); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + report = razer_chroma_standard_set_led_effect(NOSTORE, MACRO_LED, enabled); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + report = razer_chroma_standard_set_led_effect(NOSTORE, MACRO_LED, enabled); + razer_send_payload(usb_dev, &report); + + report = razer_chroma_standard_set_led_blinking(NOSTORE, MACRO_LED); + break; + + default: + report = razer_chroma_standard_set_led_effect(VARSTORE, MACRO_LED, enabled); + break; + } + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Read device file "macro_mode_effect" + * + * Returns a string + */ +ssize_t razer_attr_read_mode_macro_effect(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_standard_get_led_effect(VARSTORE, MACRO_LED); + struct razer_report response = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Write device file "mode_pulsate" + * + * The brightness oscillates between fully on and fully off generating a pulsing effect + */ +ssize_t razer_attr_write_mode_pulsate(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, 0x02); + razer_send_payload(usb_dev, &report); + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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: + report = razer_chroma_standard_set_led_effect(VARSTORE, LOGO_LED, 0x02); + break; + } + + return count; +} + +/** + * Read device file "mode_pulsate" + * + * Returns a string + */ +ssize_t razer_attr_read_mode_pulsate(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_standard_get_led_effect(VARSTORE, LOGO_LED); + struct razer_report response = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "profile_led_red" + * + * Actually a Yellow LED + * + * Returns a string + */ +ssize_t razer_attr_read_tartarus_profile_led_red(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_standard_get_led_state(VARSTORE, RED_PROFILE_LED); + struct razer_report response = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "profile_led_green" + * + * Returns a string + */ +ssize_t razer_attr_read_tartarus_profile_led_green(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_standard_get_led_state(VARSTORE, GREEN_PROFILE_LED); + struct razer_report response = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "profile_led_blue" + * + * Returns a string + */ +ssize_t razer_attr_read_tartarus_profile_led_blue(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_standard_get_led_state(VARSTORE, BLUE_PROFILE_LED); + struct razer_report response = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "%d\n", response.arguments[2]); +} + +/** + * Read device file "get_firmware_version" + * + * Returns a string + */ +ssize_t razer_attr_read_get_firmware_version(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_standard_get_firmware_version(); + struct razer_report response_report = razer_send_payload(usb_dev, &report); + + return sprintf(buf, "v%d.%d\n", response_report.arguments[0], response_report.arguments[1]); +} + +/** + * Write device file "mode_none" + * + * No keyboard effect is activated whenever this file is written to + */ +ssize_t razer_attr_write_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = {0}; + razer_chroma_standard_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + 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_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + report = razer_chroma_standard_set_led_state(VARSTORE, BACKLIGHT_LED, OFF); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + report = razer_chroma_standard_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + break; + + default: + report = razer_chroma_standard_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_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 + */ +ssize_t razer_attr_write_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, int count, int speed) +{ + unsigned char direction = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction, speed); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + report = razer_chroma_standard_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + 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_CHROMA_V2: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction, speed); + report.transaction_id.id = 0x1F; + break; + + default: + report = razer_chroma_standard_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + break; + } + razer_send_payload(usb_dev, &report); + + return count; +} +/** + * Write device file "mode_spectrum" + * + * Specrum effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + report = razer_chroma_standard_set_led_state(VARSTORE, BACKLIGHT_LED, ON); + razer_send_payload(usb_dev, &report); + report = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, LED_SPECTRUM_CYCLING); + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x1F; // TODO move to a usb_device variable + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + report = razer_chroma_standard_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + break; + + default: + report = razer_chroma_standard_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + break; + } + + razer_send_payload(usb_dev, &report); + + 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 + */ +ssize_t razer_attr_write_mode_reactive(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + if (count == 4) + { + unsigned char speed = (unsigned char)buf[0]; + switch (product) + { + 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_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb *)&buf[1]); + 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_CHROMA_V2: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb *)&buf[1]); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + report = razer_chroma_standard_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb *)&buf[1]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + break; + default: + report = razer_chroma_standard_matrix_effect_reactive(VARSTORE, BACKLIGHT_LED, speed, (struct razer_rgb *)&buf[1]); + break; + } + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Reactive only accepts Speed, RGB (4byte)\n"); + } + + return count; +} + +/** + * Write device file "mode_static" + * + * Set the keyboard to mode when 3 RGB bytes are written + */ +ssize_t razer_attr_write_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + report = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, 0x00); + razer_send_payload(usb_dev, &report); + 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 + report = razer_chroma_standard_set_led_effect(VARSTORE, LOGO_LED, 0x00); + razer_send_payload(usb_dev, &report); + 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_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_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_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + if (count == 3) + { + report = razer_chroma_standard_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + if (count == 3) + { + report = razer_chroma_standard_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + 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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + if (count == 3) + { + report = razer_chroma_extended_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + if (count == 3) + { + report = razer_chroma_extended_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x1F; + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + if (count == 3) + { + report = razer_chroma_standard_set_led_state(VARSTORE, BACKLIGHT_LED, ON); + razer_send_payload(usb_dev, &report); + report = razer_chroma_standard_set_led_effect(VARSTORE, BACKLIGHT_LED, LED_STATIC); + razer_send_payload(usb_dev, &report); + report = razer_chroma_standard_set_led_rgb(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + } + else + printf("razerkbd: Static mode only accepts RGB (3byte)\n"); + break; + + default: + printf("razerkbd: Cannot set static mode for this device\n"); + break; + } + + return count; +} + +/** + * Write device file "mode_static" + * + * ** NOSTORE version for efficiency in custom lighting configurations + * + * Set the keyboard to mode when 3 RGB bytes are written + */ +ssize_t razer_attr_write_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_ORBWEAVER: + case USB_DEVICE_ID_RAZER_DEATHSTALKER_EXPERT: + report = razer_chroma_standard_set_led_effect(NOSTORE, BACKLIGHT_LED, 0x00); + razer_send_payload(usb_dev, &report); + 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 + report = razer_chroma_standard_set_led_effect(NOSTORE, LOGO_LED, 0x00); + razer_send_payload(usb_dev, &report); + 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_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_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_TARTARUS: + case USB_DEVICE_ID_RAZER_TARTARUS_CHROMA: + case USB_DEVICE_ID_RAZER_ORBWEAVER_CHROMA: + if (count == 3) + { + report = razer_chroma_standard_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + if (count == 3) + { + report = razer_chroma_standard_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + 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_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + if (count == 3) + { + report = razer_chroma_extended_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + if (count == 3) + { + report = razer_chroma_extended_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x1F; + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Static mode only accepts RGB (3byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_ANANSI: + if (count == 3) + { + report = razer_chroma_standard_set_led_state(NOSTORE, BACKLIGHT_LED, ON); + razer_send_payload(usb_dev, &report); + report = razer_chroma_standard_set_led_effect(NOSTORE, BACKLIGHT_LED, LED_STATIC); + razer_send_payload(usb_dev, &report); + report = razer_chroma_standard_set_led_rgb(NOSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + } + else + printf("razerkbd: Static mode only accepts RGB (3byte)\n"); + break; + + default: + printf("razerkbd: Cannot set static mode for this device\n"); + break; + } + + return count; +} + +/** +* Write device file "mode_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 +*/ +ssize_t razer_attr_write_mode_starlight(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = {0}; + struct razer_rgb rgb1 = {.r = 0x00, .g = 0xFF, .b = 0x00}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_ORNATA: + if (count == 4) + { + report = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1]); + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)"); + } + 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_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + if (count == 7) + { + report = razer_chroma_extended_matrix_effect_starlight_dual(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1], (struct razer_rgb *)&buf[4]); + razer_send_payload(usb_dev, &report); + } + else if (count == 4) + { + report = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1]); + razer_send_payload(usb_dev, &report); + } + else if (count == 1) + { + report = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + if (count == 7) + { + report = 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) + { + report = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1]); + } + else if (count == 1) + { + report = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + } + else + { + printf("razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)"); + break; + } + report.transaction_id.id = 0x1F; + razer_send_payload(usb_dev, &report); + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + if (count == 7) + { + report = razer_chroma_extended_matrix_effect_starlight_dual(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1], (struct razer_rgb *)&buf[4]); + report.transaction_id.id = 0x1F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else if (count == 4) + { + report = razer_chroma_extended_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1]); + report.transaction_id.id = 0x1F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else if (count == 1) + { + report = razer_chroma_extended_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + report.transaction_id.id = 0x1F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)"); + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + if (count == 7) + { + report = razer_chroma_standard_matrix_effect_starlight_dual(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1], (struct razer_rgb *)&buf[4]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else if (count == 4) + { + report = razer_chroma_standard_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, buf[0], (struct razer_rgb *)&buf[1]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else if (count == 1) + { + report = razer_chroma_standard_matrix_effect_starlight_random(VARSTORE, BACKLIGHT_LED, buf[0]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + } + else + { + printf("razerkbd: Starlight only accepts Speed (1byte). Speed, RGB (4byte). Speed, RGB, RGB (7byte)"); + } + break; + + default: // BW2016 can do normal starlight + report = razer_chroma_standard_matrix_effect_starlight_single(VARSTORE, BACKLIGHT_LED, 0x01, &rgb1); + razer_send_payload(usb_dev, &report); + break; + } + + return count; +} + +/** + * Write device file "mode_breath" + */ +ssize_t razer_attr_write_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + case USB_DEVICE_ID_RAZER_BLACKWIDOW_LITE: + case USB_DEVICE_ID_RAZER_ORNATA: + switch (count) + { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + break; + + default: + printf("razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)"); + break; + } + break; + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + switch (count) + { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + report.transaction_id.id = 0x1F; + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + razer_send_payload(usb_dev, &report); + report.transaction_id.id = 0x1F; + break; + + case 1: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + razer_send_payload(usb_dev, &report); + report.transaction_id.id = 0x1F; + break; + + default: + printf("razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)"); + break; + } + 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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + switch (count) + { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + razer_send_payload(usb_dev, &report); + break; + + case 1: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + razer_send_payload(usb_dev, &report); + break; + + default: + printf("razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)"); + break; + } + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + if (count == 3) + { // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + } + else if (count == 6) + { // Dual colour mode + report = 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 + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + } + else + { + printf("razerkbd: Breathing only accepts '1' (1byte). RGB (3byte). RGB, RGB (6byte)"); + break; + } + report.transaction_id.id = 0x1F; + razer_send_payload(usb_dev, &report); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + switch (count) + { + case 3: // Single colour mode + report = razer_chroma_standard_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + break; + + case 6: // Dual colour mode + report = razer_chroma_standard_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + break; + + default: // "Random" colour mode + report = razer_chroma_standard_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + razer_send_payload(usb_dev, &report); + break; + // TODO move default to case 1:. Then default: printk(warning). Also remove pointless buffer + } + break; + + default: + switch (count) + { + case 3: // Single colour mode + report = razer_chroma_standard_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0]); + razer_send_payload(usb_dev, &report); + break; + + case 6: // Dual colour mode + report = razer_chroma_standard_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb *)&buf[0], (struct razer_rgb *)&buf[3]); + razer_send_payload(usb_dev, &report); + break; + + default: // "Random" colour mode + report = razer_chroma_standard_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + razer_send_payload(usb_dev, &report); + break; + // TODO move default to case 1:. Then default: printk(warning). Also remove pointless buffer + } + break; + } + + return count; +} + +ssize_t has_inverted_led_state(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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; + } +} + +/** + * Read device file "set_logo" + * + * Sets the logo lighting state to the ASCII number written to this file. + */ +ssize_t razer_attr_read_set_logo(IOUSBDeviceInterface **usb_dev, char *buf, int count) +{ + struct razer_report report = razer_chroma_standard_get_led_effect(VARSTORE, LOGO_LED); + struct razer_report response = get_empty_razer_report(); + int state; + + // Blade laptops don't use effect for logo on/off, and mode 2 ("blink") is technically unsupported. + if (is_blade_laptop(usb_dev)) + { + report = razer_chroma_standard_get_led_state(VARSTORE, LOGO_LED); + } + + response = razer_send_payload(usb_dev, &report); + state = response.arguments[2]; + + if (has_inverted_led_state(usb_dev) && (state == 0 || state == 1)) + { + state = !state; + } + + return sprintf(buf, "%d\n", state); +} + +/** + * Write device file "set_logo" + * + * Sets the logo lighting state to the ASCII number written to this file. + */ +ssize_t razer_attr_write_set_logo(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + unsigned char state = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = {0}; + + if (has_inverted_led_state(usb_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(usb_dev) && (state == 0 || state == 1)) + { + report = razer_chroma_standard_set_led_state(VARSTORE, LOGO_LED, state); + } + else + { + report = razer_chroma_standard_set_led_effect(VARSTORE, LOGO_LED, state); + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_custom" + * + * Sets the keyboard to custom mode whenever the file is written to + */ +ssize_t razer_attr_write_mode_custom(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_effect_custom_frame(); + 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_CHROMA_V2: + report = razer_chroma_extended_matrix_effect_custom_frame(); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + report = razer_chroma_standard_matrix_effect_custom_frame(VARSTORE); // Possibly could use VARSTORE + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + break; + + default: + report = razer_chroma_standard_matrix_effect_custom_frame(VARSTORE); // Possibly could use VARSTORE + break; + } + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "set_fn_toggle" + * + * Sets the logo lighting state to the ASCII number written to this file. + */ +ssize_t razer_attr_write_set_fn_toggle(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + unsigned char state = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = razer_chroma_misc_fn_key_toggle(state); + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "set_brightness" + * + * Sets the brightness to the ASCII number written to this file. + */ +ssize_t razer_attr_write_set_brightness(IOUSBDeviceInterface **usb_dev, ushort brightness, int count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + report = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + report.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_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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_brightness(VARSTORE, BACKLIGHT_LED, brightness); + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + report = razer_chroma_extended_matrix_brightness(VARSTORE, BACKLIGHT_LED, brightness); + report.transaction_id.id = 0x1F; + 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: + report = razer_chroma_standard_set_led_brightness(VARSTORE, LOGO_LED, brightness); + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + default: + if (is_blade_laptop(usb_dev)) + { + report = razer_chroma_misc_set_blade_brightness(brightness); + } + else + { + report = razer_chroma_standard_set_led_brightness(VARSTORE, BACKLIGHT_LED, brightness); + } + break; + } + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Read device file "macro_mode" + * + * Returns a string + */ +ushort razer_attr_read_set_brightness(IOUSBDeviceInterface **usb_dev) +{ + bool is_matrix_brightness = false; + unsigned char brightness = 0; + struct razer_report report = {0}; + struct razer_report response = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + + case USB_DEVICE_ID_RAZER_TARTARUS_V2: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, ZERO_LED); + report.transaction_id.id = 0x1F; + is_matrix_brightness = true; + 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_LITE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, BACKLIGHT_LED); + is_matrix_brightness = true; + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ELITE: + case USB_DEVICE_ID_RAZER_CYNOSA_V2: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x1F; + is_matrix_brightness = true; + 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: + report = razer_chroma_standard_get_led_brightness(VARSTORE, LOGO_LED); + break; + + case USB_DEVICE_ID_RAZER_NOSTROMO: + default: + if (is_blade_laptop(usb_dev)) + { + report = razer_chroma_misc_get_blade_brightness(); + } + else + { + report = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + } + break; + } + + response = razer_send_payload(usb_dev, &report); + + // Brightness is stored elsewhere for the stealth cmds + if (is_blade_laptop(usb_dev)) + { + brightness = response.arguments[1]; + } + else + { + brightness = response.arguments[2]; + } + + if(is_matrix_brightness) { + brightness = round(brightness / 2.55); + } + + return brightness; +} + +/** + * Write device file "matrix_custom_frame" + * + * Format + * ROW_ID START_COL STOP_COL RGB... + */ +ssize_t razer_attr_write_matrix_custom_frame(IOUSBDeviceInterface **usb_dev, const char *buf, int count) +{ + struct razer_report report; + int offset = 0; + unsigned char row_id; + unsigned char start_col; + unsigned char stop_col; + unsigned char row_length; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + //printk(KERN_ALERT "razerkbd: Total count: %d\n", (unsigned char)count); + + while (offset < count) + { + if (offset + 3 > count) + { + printf("razerkbd: Wrong Amount of data provided: Should be ROW_ID, START_COL, STOP_COL, N_RGB\n"); + break; + } + + row_id = buf[offset++]; + start_col = buf[offset++]; + stop_col = buf[offset++]; + row_length = ((stop_col + 1) - start_col) * 3; + + // printk(KERN_ALERT "razerkbd: Row ID: %d, Start: %d, Stop: %d, row length: %d\n", row_id, start_col, stop_col, row_length); + + if (start_col > stop_col) + { + printf("razerkbd: Start column is greater than end column\n"); + break; + } + + if (offset + row_length > count) + { + printf("razerkbd: Not enough RGB to fill row\n"); + break; + } + + // Offset now at beginning of RGB data + switch (product) + { + 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_BLACKWIDOW_V3: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char *)&buf[offset]); + 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_CHROMA_V2: + report = razer_chroma_extended_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char *)&buf[offset]); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_DEATHSTALKER_CHROMA: + report = razer_chroma_misc_one_row_set_custom_frame(start_col, stop_col, (unsigned char *)&buf[offset]); + break; + + case USB_DEVICE_ID_RAZER_BLADE_LATE_2016: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_CHROMA_V2: + report = razer_chroma_standard_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char *)&buf[offset]); + report.transaction_id.id = 0x3F; // TODO move to a usb_device variable + break; + + case USB_DEVICE_ID_RAZER_BLACKWIDOW_X_ULTIMATE: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE_2016: + 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_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_MID_2019_MERCURY: + case USB_DEVICE_ID_RAZER_BLADE_STUDIO_EDITION_2019: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017: + case USB_DEVICE_ID_RAZER_BLADE_PRO_2017_FULLHD: + report.transaction_id.id = 0x80; // Fall into the 2016/blade/blade2016 to set device id + /* fall through */ + default: + report = razer_chroma_standard_matrix_set_custom_frame(row_id, start_col, stop_col, (unsigned char *)&buf[offset]); + break; + } + razer_send_payload(usb_dev, &report); + + // *3 as its 3 bytes per col (RGB) + offset += row_length; + } + + return count; +} + +/** + * Send report to the keyboard + */ +static int razer_get_report(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report, struct razer_report *response_report) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + uint report_index; + uint response_index; + + switch (product) + { + case USB_DEVICE_ID_RAZER_ANANSI: + case USB_DEVICE_ID_RAZER_HUNTSMAN_TE: + case USB_DEVICE_ID_RAZER_ORNATA_CHROMA_V2: + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3_TK: + case USB_DEVICE_ID_RAZER_HUNTSMAN_MINI: + report_index = 0x02; + response_index = 0x02; + break; + case USB_DEVICE_ID_RAZER_BLACKWIDOW_V3: + report_index = 0x03; + response_index = 0x03; + break; + default: + report_index = 0x01; + response_index = 0x01; + break; + } + + return razer_get_usb_response(usb_dev, report_index, request_report, response_index, response_report, RAZER_BLACKWIDOW_CHROMA_WAIT_MIN_US); +} + +/** + * Function to send to device, get response, and actually check the response + */ +static struct razer_report razer_send_payload(IOUSBDeviceInterface **dev, struct razer_report *request_report) +{ + IOReturn retval = -1; + + struct razer_report response_report = {0}; + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(dev, request_report, &response_report); + + if (retval == kIOReturnSuccess) + { + // 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 doesnt match request (keyboard)\n"); + } else if (response_report.status == RAZER_CMD_BUSY) { + //printf("Device is busy (keyboard)\n"); + } else if (response_report.status == RAZER_CMD_FAILURE) { + printf("Command failed (keyboard)\n"); + } else if (response_report.status == RAZER_CMD_NOT_SUPPORTED) { + printf("Command not supported (keyboard)\n"); + } else if (response_report.status == RAZER_CMD_TIMEOUT) { + printf("Command timed out (keyboard)\n"); + } + } else { + printf("Invalid Report Length (keyboard)\n"); + } + + return response_report; +} diff --git a/src/lib/razerkraken_driver.c b/src/lib/razerkraken_driver.c new file mode 100644 index 0000000..df7d9e1 --- /dev/null +++ b/src/lib/razerkraken_driver.c @@ -0,0 +1,324 @@ +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to Terry Cain <[email protected]> + */ +#include <stdio.h> +#include <string.h> + +#include "razerkraken_driver.h" +#include "razercommon.h" + +/** + * Send USB control report to the keyboard + * USUALLY index = 0x02 + * FIREFLY is 0 + */ +IOReturn razer_kraken_send_control_msg(IOUSBDeviceInterface **dev, struct razer_kraken_request_report* data, unsigned char skip) { + IOUSBDevRequest request; + + request.bRequest = HID_REQ_SET_REPORT; // 0x09 + request.bmRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT; + request.wValue = 0x0204; + request.wIndex = 0x0003; + request.wLength = 37; + request.pData = (void*)data; + + IOReturn result = (*dev)->DeviceRequest(dev, &request); + + // Wait + if(skip != 1) { + usleep(data->length * 15 * 1000); + } + return result; +} + +static struct razer_kraken_device get_kraken_device(IOUSBDeviceInterface **dev) +{ + UInt16 product = -1; + (*dev)->GetDeviceProduct(dev, &product); + + struct razer_kraken_device device; + device.usb_pid = product; + + switch (product) + { + case USB_DEVICE_ID_RAZER_KRAKEN_V2: + device.led_mode_address = KYLIE_SET_LED_ADDRESS; + device.custom_address = KYLIE_CUSTOM_ADDRESS_START; + device.breathing_address[0] = KYLIE_BREATHING1_ADDRESS_START; + device.breathing_address[1] = KYLIE_BREATHING2_ADDRESS_START; + device.breathing_address[2] = KYLIE_BREATHING3_ADDRESS_START; + break; + } + + return device; +} + +/** + * 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; +} + +/** + * Write device file "mode_spectrum" + * + * Specrum effect mode is activated whenever the file is written to + */ +ssize_t razer_kraken_attr_write_mode_spectrum(IOUSBDeviceInterface **dev, const char *buf, size_t count) +{ + struct razer_kraken_device device = get_kraken_device(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 + razer_kraken_send_control_msg(dev, &report, 0); + + return count; +} + +/** + * Write device file "mode_none" + * + * None effect mode is activated whenever the file is written to + */ +ssize_t razer_kraken_attr_write_mode_none(IOUSBDeviceInterface **dev, const char *buf, size_t count) +{ + struct razer_kraken_device device = get_kraken_device(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 + razer_kraken_send_control_msg(dev, &report, 0); + + return count; +} + + +/** + * Write device file "mode_static" + * + * Static effect mode is activated whenever the file is written to with 3 bytes + */ +ssize_t razer_kraken_attr_write_mode_static(IOUSBDeviceInterface **dev, const char *buf, size_t count) +{ + struct razer_kraken_device device = get_kraken_device(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) { + + 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; + + // 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_V2: + razer_kraken_send_control_msg(dev, &rgb_report, 0); + break; + } + // Send Set static command + razer_kraken_send_control_msg(dev, &effect_report, 0); + + } else { + printf("razerkraken: Static mode only accepts RGB (3byte) or RGB with intensity (4byte)\n"); + } + + return count; +} + +/** + * Write device file "mode_custom" + * + * Custom effect mode is activated whenever the file is written to with 3 bytes + */ +ssize_t razer_kraken_attr_write_mode_custom(IOUSBDeviceInterface **dev, const char *buf, size_t count) +{ + struct razer_kraken_device device = get_kraken_device(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) { + + 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] = 1; //effect_byte.value; + + // Lock sending of the 2 commands + razer_kraken_send_control_msg(dev, &rgb_report, 1); + razer_kraken_send_control_msg(dev, &effect_report, 1); + + } else { + printf("razerkraken: Custom mode only accepts RGB (3byte) or RGB with intensity (4byte)\n"); + } + + return count; +} + + +/** + * Write device file "mode_breath" + * + * Breathing effect mode is activated whenever the file is written to with 3,6 or 9 bytes + */ +ssize_t razer_kraken_attr_write_mode_breath(IOUSBDeviceInterface **dev, const char *buf, size_t count) +{ + struct razer_kraken_device device = get_kraken_device(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) { + printf("razerkraken: Breathing mode only accepts RGB (3byte)\n"); + return count; + } + + 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 + razer_kraken_send_control_msg(dev, &rgb_report, 0); + + razer_kraken_send_control_msg(dev, &effect_report, 0); + } 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 + razer_kraken_send_control_msg(dev, &rgb_report, 0); + + razer_kraken_send_control_msg(dev, &rgb_report2, 0); + + razer_kraken_send_control_msg(dev, &effect_report, 0); + + } 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 + razer_kraken_send_control_msg(dev, &rgb_report, 0); + + razer_kraken_send_control_msg(dev, &rgb_report2, 0); + + razer_kraken_send_control_msg(dev, &rgb_report3, 0); + + razer_kraken_send_control_msg(dev, &effect_report, 0); + + } else { + printf("razerkraken: Breathing mode only accepts RGB (3byte), RGB RGB (6byte) or RGB RGB RGB (9byte)\n"); + } + + return count; +}
\ No newline at end of file diff --git a/src/lib/razermouse_driver.c b/src/lib/razermouse_driver.c new file mode 100644 index 0000000..68002d9 --- /dev/null +++ b/src/lib/razermouse_driver.c @@ -0,0 +1,2210 @@ +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to Terry Cain <[email protected]> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "razermouse_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/** + * Static values for mouse devices + */ +// Setup orochi2011 +int orochi2011_dpi = 0x4c; +int orochi2011_poll = 500; + +// Setup default values for DeathAdder 3.5G +DeathAdder3_5g da3_5g = { + .leds = 3, // Lights up all lights + .dpi = 1, // 3500 DPI + .profile = 1, // Profile 1 + .poll = 1 // Poll rate 1000 +}; + +/** + * Send report to the mouse + */ +static int razer_get_report(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report, struct razer_report *response_report) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) { + // These devices require longer waits to read their firmware, serial, and other setting values + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_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_BASILISK_ULTIMATE_RECEIVER: + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_NEW_MOUSE_RECEIVER_WAIT_MIN_US); + break; + + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_VIPER_MOUSE_RECEIVER_WAIT_MIN_US); + break; + + default: + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_MOUSE_WAIT_MIN_US); + } +} + +/** + * Function to send to device, get response, and actually check the response + */ +static struct razer_report razer_send_payload(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report) +{ + IOReturn retval = -1; + + struct razer_report response_report = {0}; + + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(usb_dev, request_report, &response_report); + + 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 (mouse)\n"); + } else if (response_report.status == RAZER_CMD_BUSY) { + //printf("Device is busy (mouse)\n"); + } else if (response_report.status == RAZER_CMD_FAILURE) { + printf("Command failed (mouse)\n"); + } else if (response_report.status == RAZER_CMD_NOT_SUPPORTED) { + printf("Command not supported (mouse)\n"); + } else if (response_report.status == RAZER_CMD_TIMEOUT) { + printf("Command timed out (mouse)\n"); + } + } else { + printf("Invalid Report Length (mouse)\n"); + } + + return response_report; +} + +ssize_t razer_attr_write_side_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int side) +{ + unsigned char direction = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + 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_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, side, direction, 0x28); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, side, direction, 0x28); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_wave not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +ssize_t razer_attr_write_side_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int side) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_static(VARSTORE, side, (struct razer_rgb*)&buf[0]); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + 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: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, side, (struct razer_rgb*)&buf[0]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, side, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_static not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermouse: Static mode only accepts RGB (3byte)\n"); + } + return count; +} + +ssize_t razer_attr_write_side_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int side) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_static(NOSTORE, side, (struct razer_rgb*)&buf[0]); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + 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: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, side, (struct razer_rgb*)&buf[0]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, side, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: side_mode_static_no_store not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermouse: Static mode only accepts RGB (3byte)\n"); + } + return count; +} + +ssize_t razer_attr_write_side_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int side) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_spectrum(VARSTORE, side); + 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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, side); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, side); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: side_mode_spectrum not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +ssize_t razer_attr_write_side_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int side) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_single(VARSTORE, side, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_dual(VARSTORE, side, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_random(VARSTORE, side); + break; + } + 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_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + 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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, side, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, side, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, side); + break; + } + break; + } + + switch(product) { + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report.transaction_id.id = 0x1f; + break; + + default: + report.transaction_id.id = 0x3f; + break; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +ssize_t razer_attr_write_side_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int side) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_none(VARSTORE, LOGO_LED); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, side); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, side); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_none not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "logo_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_logo_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + unsigned char direction = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + 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_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, LOGO_LED, direction, 0x28); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, LOGO_LED, direction, 0x28); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_wave not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "scroll_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_scroll_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + unsigned char direction = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + 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_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, SCROLL_WHEEL_LED, direction, 0x28); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, SCROLL_WHEEL_LED, direction, 0x28); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_wave not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "left_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_left_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_wave(usb_dev, 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 + */ +ssize_t razer_attr_write_right_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_wave(usb_dev, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "logo_mode_static" (for extended mouse matrix effects) + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +ssize_t razer_attr_write_logo_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_static(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + report = razer_chroma_standard_set_led_rgb(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x3F; + break; + default: + printf("razermouse: logo_mode_static not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermouse: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "logo_mode_static" (for extended mouse matrix effects) + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +ssize_t razer_attr_write_scroll_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_static(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + report = razer_chroma_standard_set_led_rgb(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x3F; + break; + + default: + printf("razermouse: logo_mode_static not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermouse: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "left_mode_wave" (for extended mouse matrix effects) + * + * Wave effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_left_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_static(usb_dev, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_static" (for extended mouse matrix effects) + * + * Static effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_right_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_static(usb_dev, buf, count, RIGHT_SIDE_LED); +} + + +/** + * Write device file "logo_mode_static" (for extended mouse matrix effects) + * + * ** NOSTORE version for efficiency in custom lighting configurations + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +ssize_t razer_attr_write_logo_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_static(NOSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + report = razer_chroma_standard_set_led_rgb(NOSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_static not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermouse: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "logo_mode_static" (for extended mouse matrix effects) + * + * ** NOSTORE version for efficiency in custom lighting configurations + * + * Set the mouse to static mode when 3 RGB bytes are written + */ +ssize_t razer_attr_write_scroll_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_static(NOSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x1f; + break; + case USB_DEVICE_ID_RAZER_ABYSSUS_V2: + report = razer_chroma_standard_set_led_rgb(NOSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x3F; + break; + + default: + printf("razermouse: logo_mode_static not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermouse: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "left_mode_no_store" (for extended mouse matrix effects) + * + * NOSTORE version for efficiency in custom lighting configurations + */ +ssize_t razer_attr_write_left_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_static_no_store(usb_dev, buf, count, LEFT_SIDE_LED); +} + +/** + * Write device file "right_mode_no_store" (for extended mouse matrix effects) + * + * NOSTORE version for efficiency in custom lighting configurations + */ +ssize_t razer_attr_write_right_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_static_no_store(usb_dev, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "logo_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_logo_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_spectrum(VARSTORE, LOGO_LED); + 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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, LOGO_LED); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, LOGO_LED); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_spectrum not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "logo_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_scroll_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_spectrum(VARSTORE, SCROLL_WHEEL_LED); + 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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, SCROLL_WHEEL_LED); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, SCROLL_WHEEL_LED); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_spectrum not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "left_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +ssize_t razer_attr_write_left_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_spectrum(usb_dev, 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 + */ +ssize_t razer_attr_write_right_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_spectrum(usb_dev, buf, count, RIGHT_SIDE_LED); +} + + +/** + * Write device file "logo_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +ssize_t razer_attr_write_logo_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_single(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_dual(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_random(VARSTORE, LOGO_LED); + break; + } + 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_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + 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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, LOGO_LED); + break; + } + break; + } + + switch(product) { + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report.transaction_id.id = 0x1f; + break; + + default: + report.transaction_id.id = 0x3f; + break; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "scroll_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +ssize_t razer_attr_write_scroll_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_single(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_dual(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_mouse_extended_matrix_effect_breathing_random(VARSTORE, SCROLL_WHEEL_LED); + break; + } + 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_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_ESSENTIAL: + 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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_extended_matrix_effect_breathing_dual(VARSTORE, SCROLL_WHEEL_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, SCROLL_WHEEL_LED); + break; + } + break; + } + + switch(product) { + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report.transaction_id.id = 0x1f; + break; + + default: + report.transaction_id.id = 0x3f; + break; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "left_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +ssize_t razer_attr_write_left_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_breath(usb_dev, 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 + */ +ssize_t razer_attr_write_right_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_breath(usb_dev, buf, count, RIGHT_SIDE_LED); +} + +/** + * Write device file "logo_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +ssize_t razer_attr_write_logo_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_none(VARSTORE, LOGO_LED); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, LOGO_LED); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, LOGO_LED); + report.transaction_id.id = 0x1f; + break; + + + default: + printf("razermouse: logo_mode_none not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "logo_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +ssize_t razer_attr_write_scroll_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_none(VARSTORE, SCROLL_WHEEL_LED); + 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_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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, SCROLL_WHEEL_LED); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, SCROLL_WHEEL_LED); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_none not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "left_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +ssize_t razer_attr_write_left_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_none(usb_dev, 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 + */ +ssize_t razer_attr_write_right_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_none(usb_dev, buf, count, RIGHT_SIDE_LED); +} + +// These are for older mice, eg DeathAdder 2013 + +/** + * Write device file "scroll_led_effect" + */ +ssize_t razer_attr_write_scroll_led_effect(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + unsigned char effect = (unsigned char)strtoul(buf, NULL, 10); + struct razer_report report = razer_chroma_standard_set_led_effect(VARSTORE, SCROLL_WHEEL_LED, effect); + report.transaction_id.id = 0x3F; + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "logo_led_effect" + */ +ssize_t razer_attr_write_logo_led_effect(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + unsigned char effect = (unsigned char)strtoul(buf, NULL, 10); + struct razer_report report = razer_chroma_standard_set_led_effect(VARSTORE, LOGO_LED, effect); + report.transaction_id.id = 0x3F; + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "logo_led_rgb" + */ +ssize_t razer_attr_write_logo_led_rgb(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + if(count == 3) { + report = razer_chroma_standard_set_led_rgb(VARSTORE, LOGO_LED, (struct razer_rgb*)&buf[0]); + report.transaction_id.id = 0x3F; + razer_send_payload(usb_dev, &report); + } else { + printf("razermouse: Logo LED mode only accepts RGB (3byte)\n"); + } + + 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 + */ +ssize_t razer_attr_write_logo_mode_reactive(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 4) { + unsigned char speed = (unsigned char)buf[0]; + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_mouse_extended_matrix_effect_reactive(VARSTORE, LOGO_LED, speed, (struct razer_rgb*)&buf[1]); + 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_8KHZ: + case USB_DEVICE_ID_RAZER_VIPER_MINI: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRED: + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_VIPER_ULTIMATE_WIRELESS: + case USB_DEVICE_ID_RAZER_BASILISK: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_MINI: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, LOGO_LED, speed, (struct razer_rgb*)&buf[1]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, LOGO_LED, speed, (struct razer_rgb*)&buf[1]); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: logo_mode_reactive not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + + } else { + printf("razermouse: Reactive only accepts Speed, RGB (4byte)\n"); + } + 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 + */ +ssize_t razer_attr_write_scroll_mode_reactive(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 4) { + unsigned char speed = (unsigned char)buf[0]; + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + case USB_DEVICE_ID_RAZER_NAGA_CHROMA: + report = razer_chroma_mouse_extended_matrix_effect_reactive(VARSTORE, SCROLL_WHEEL_LED, speed, (struct razer_rgb*)&buf[1]); + 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_BASILISK: + 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: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, SCROLL_WHEEL_LED, speed, (struct razer_rgb*)&buf[1]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, SCROLL_WHEEL_LED, speed, (struct razer_rgb*)&buf[1]); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: scroll_mode_reactive not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + + } else { + printf("razermouse: Reactive only accepts Speed, RGB (4byte)\n"); + } + return count; +} + +ssize_t razer_attr_write_side_mode_reactive(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count, int side) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 4) { + unsigned char speed = (unsigned char)buf[0]; + + switch(product) { + 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: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, side, speed, (struct razer_rgb*)&buf[1]); + break; + + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_effect_reactive(VARSTORE, side, speed, (struct razer_rgb*)&buf[1]); + report.transaction_id.id = 0x1f; + break; + + default: + printf("razermouse: left/right mode_reactive not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + + } else { + printf("razermouse: Reactive only accepts Speed, RGB (4byte)\n"); + } + return count; +} + +/** + * 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 + */ +ssize_t razer_attr_write_left_mode_reactive(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_reactive(usb_dev, 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 + */ +ssize_t razer_attr_write_right_mode_reactive(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + return razer_attr_write_side_mode_reactive(usb_dev, buf, count, RIGHT_SIDE_LED); +} + +ushort razer_attr_read_dpi(IOUSBDeviceInterface **usb_dev) +{ + struct razer_report report, response_report; + report = razer_chroma_misc_get_dpi_xy(0x01); + response_report = razer_send_payload(usb_dev, &report); + ushort dpi_x = (response_report.arguments[1] << 8) | (response_report.arguments[2] & 0xFF); + return dpi_x; +} + +void razer_attr_write_dpi(IOUSBDeviceInterface **usb_dev, ushort dpi_x, ushort dpi_y) +{ + struct razer_report report = razer_chroma_misc_set_dpi_xy(0x01, dpi_x, dpi_y); + razer_send_payload(usb_dev, &report); +} + +ssize_t razer_attr_read_get_battery(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_misc_get_battery_level(); + struct razer_report response_report = {0}; + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) + { + 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_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + report.transaction_id.id = 0x3f; + break; + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + report.transaction_id.id = 0x1f; + break; + } + response_report = razer_send_payload(usb_dev, &report); + return sprintf(buf, "%d\n", response_report.arguments[1]); +} + +/** + * Read device file "is_charging" + * + * Returns 0 when not charging, 1 when charging + */ +ssize_t razer_attr_read_is_charging(IOUSBDeviceInterface **usb_dev, char *buf) +{ + struct razer_report report = razer_chroma_misc_get_charging_status(); + struct razer_report response_report = {0}; + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + 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_BASILISK_ULTIMATE: + case USB_DEVICE_ID_RAZER_BASILISK_ULTIMATE_RECEIVER: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRED: + case USB_DEVICE_ID_RAZER_DEATHADDER_V2_PRO_WIRELESS: + report.transaction_id.id = 0x3f; + break; + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_RECEIVER: + case USB_DEVICE_ID_RAZER_LANCEHEAD_WIRELESS_WIRED: + report.transaction_id.id = 0x1f; + break; + } + + response_report = razer_send_payload(usb_dev, &report); + return sprintf(buf, "%d\n", response_report.arguments[1]); +} + +/** + * Read device file "poll_rate" + * + * Returns a string + */ +ushort razer_attr_read_poll_rate(IOUSBDeviceInterface **usb_dev) +{ + struct razer_report report = razer_chroma_misc_get_polling_rate(); + struct razer_report response_report = {0}; + unsigned short polling_rate = 0; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + switch(product) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + switch(da3_5g.poll) { + case 0x01: + polling_rate = 1000; + break; + case 0x02: + polling_rate = 500; + break; + case 0x03: + polling_rate = 125; + break; + } + return 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_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: + report.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report.transaction_id.id = 0x1f; + break; + } + + if(product == USB_DEVICE_ID_RAZER_OROCHI_2011) { + response_report.arguments[0] = orochi2011_poll; + } else { + response_report = razer_send_payload(usb_dev, &report); + } + + switch(response_report.arguments[0]) { + case 0x01: + polling_rate = 1000; + break; + case 0x02: + polling_rate = 500; + break; + case 0x08: + polling_rate = 125; + break; + } + + return polling_rate; +} + +void deathadder3_5g_set_poll_rate(IOUSBDeviceInterface **usb_dev, unsigned short poll_rate) +{ + switch(poll_rate) { + case 1000: + da3_5g.poll = 1; + break; + case 500: + da3_5g.poll = 2; + break; + case 125: + da3_5g.poll = 3; + break; + default: // 500 + da3_5g.poll = 2; + break; + } + + razer_send_control_msg_old_device(usb_dev, &da3_5g, 0x10, 0x00, 4); +} + +/** + * Write device file "poll_rate" + * + * Sets the poll rate + */ +void razer_attr_write_poll_rate(IOUSBDeviceInterface **usb_dev, ushort polling_rate) +{ + struct razer_report report = razer_chroma_misc_set_polling_rate(polling_rate); + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_DEATHADDER_3_5G: + deathadder3_5g_set_poll_rate(usb_dev, polling_rate); + return; + + case USB_DEVICE_ID_RAZER_OROCHI_2011: + orochi2011_poll = polling_rate; + report = razer_chroma_misc_set_orochi2011_poll_dpi(orochi2011_poll, orochi2011_dpi, orochi2011_dpi); + 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_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: + report.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_ATHERIS_RECEIVER: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report.transaction_id.id = 0x1f; + break; + } + + razer_send_payload(usb_dev, &report); +} + +/** + * Write device file "matrix_brightness" + * + * Sets the brightness to the ASCII number written to this file. + */ + +void razer_attr_write_matrix_brightness(IOUSBDeviceInterface **usb_dev, unsigned char brightness) +{ + brightness = round(brightness * 2.55); + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + report = razer_chroma_misc_set_dock_brightness(brightness); + break; + + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + // Orochi sets brightness of scroll wheel apparently + report = razer_chroma_standard_set_led_brightness(VARSTORE, SCROLL_WHEEL_LED, brightness); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_standard_set_led_brightness(VARSTORE, BACKLIGHT_LED, brightness); + report.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + report = razer_chroma_extended_matrix_brightness(VARSTORE, 0x00, brightness); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + // Naga Trinity uses the LED 0x00 and Matrix Brightness + report = razer_chroma_extended_matrix_brightness(VARSTORE, 0x00, brightness); + break; + + default: + report = razer_chroma_standard_set_led_brightness(VARSTORE, BACKLIGHT_LED, brightness); + break; + } + razer_send_payload(usb_dev, &report); +} + +/** + * Read device file "matrix_brightness" + * + * Returns a string + */ +ushort razer_attr_read_matrix_brightness(IOUSBDeviceInterface **usb_dev) +{ + struct razer_report report = {0}; + struct razer_report response = {0}; + unsigned char brightness_index = 0x02; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_MAMBA_WIRELESS: + report = razer_chroma_misc_get_dock_brightness(); + brightness_index = 0x00; + break; + + case USB_DEVICE_ID_RAZER_OROCHI_CHROMA: + // Orochi sets brightness of scroll wheel apparently + report = razer_chroma_standard_get_led_brightness(VARSTORE, SCROLL_WHEEL_LED); + break; + + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + // Orochi sets brightness of scroll wheel apparently + report = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + report.transaction_id.id = 0x3f; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, 0x00); + report.transaction_id.id = 0x1F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_TRINITY: + // Naga Trinity uses the LED 0x00 and Matrix Brightness + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, 0x00); + break; + + default: + report = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + break; + } + response = razer_send_payload(usb_dev, &report); + + if (response.status != RAZER_CMD_SUCCESSFUL) { + return 0; + } + // Brightness is at arg[0] for dock and arg[1] for led_brightness + ushort brightness = response.arguments[brightness_index]; + brightness = round(brightness / 2.55); + return brightness; +} + +/** + * Read device file "scroll_led_brightness" + */ +ushort razer_attr_read_scroll_led_brightness(IOUSBDeviceInterface **usb_dev) +{ + struct razer_report report = razer_chroma_standard_get_led_brightness(VARSTORE, SCROLL_WHEEL_LED); + struct razer_report response = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_standard_get_led_brightness(VARSTORE, SCROLL_WHEEL_LED); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, SCROLL_WHEEL_LED); + report.transaction_id.id = 0x1f; + break; + + 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_WHITE_EDITION: + 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_DEATHADDER_V2: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, SCROLL_WHEEL_LED); + break; + + default: + report = razer_chroma_standard_get_led_brightness(VARSTORE, SCROLL_WHEEL_LED); + break; + } + + response = razer_send_payload(usb_dev, &report); + + ushort brightness = response.arguments[2]; + brightness = round(brightness / 2.55); + return brightness; +} + +/** + * Write device file "scroll_led_brightness" + */ +void razer_attr_write_scroll_led_brightness(IOUSBDeviceInterface **usb_dev, unsigned char brightness) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_standard_set_led_brightness(VARSTORE, SCROLL_WHEEL_LED, brightness); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_brightness(VARSTORE, SCROLL_WHEEL_LED, brightness); + report.transaction_id.id = 0x1f; + break; + + 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_WHITE_EDITION: + 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_DEATHADDER_V2: + report = razer_chroma_extended_matrix_brightness(VARSTORE, SCROLL_WHEEL_LED, brightness); + break; + + default: + report = razer_chroma_standard_set_led_brightness(VARSTORE, SCROLL_WHEEL_LED, brightness); + break; + } + + razer_send_payload(usb_dev, &report); +} + +/** + * Read device file "logo_led_brightness" + */ +ushort razer_attr_read_logo_led_brightness(IOUSBDeviceInterface **usb_dev) +{ + struct razer_report report = {0}; + struct razer_report response = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_standard_get_led_brightness(VARSTORE, LOGO_LED); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, LOGO_LED); + report.transaction_id.id = 0x1f; + break; + + 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_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_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: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, LOGO_LED); + break; + + default: + report = razer_chroma_standard_get_led_brightness(VARSTORE, LOGO_LED); + break; + } + + response = razer_send_payload(usb_dev, &report); + + ushort brightness = response.arguments[2]; + brightness = round(brightness / 2.55); + return brightness; +} + +/** + * Write device file "logo_led_brightness" + */ +void razer_attr_write_logo_led_brightness(IOUSBDeviceInterface **usb_dev, unsigned char brightness) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_NAGA_HEX_V2: + report = razer_chroma_standard_set_led_brightness(VARSTORE, LOGO_LED, brightness); + report.transaction_id.id = 0x3F; + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + case USB_DEVICE_ID_RAZER_BASILISK_V2: + report = razer_chroma_extended_matrix_brightness(VARSTORE, LOGO_LED, brightness); + report.transaction_id.id = 0x1f; + break; + + 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_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_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: + report = razer_chroma_extended_matrix_brightness(VARSTORE, LOGO_LED, brightness); + break; + + default: + report = razer_chroma_standard_set_led_brightness(VARSTORE, LOGO_LED, brightness); + break; + } + + razer_send_payload(usb_dev, &report); +} + +ushort razer_attr_read_side_led_brightness(IOUSBDeviceInterface **usb_dev, int side) +{ + struct razer_report report = {0}; + struct razer_report response = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + 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: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, side); + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + report = razer_chroma_extended_matrix_get_brightness(VARSTORE, side); + report.transaction_id.id = 0x1f; + break; + + default: + report = razer_chroma_standard_get_led_brightness(VARSTORE, side); + break; + } + + response = razer_send_payload(usb_dev, &report); + + ushort brightness = response.arguments[2]; + brightness = round(brightness / 2.55); + return brightness; +} + +void razer_attr_write_side_led_brightness(IOUSBDeviceInterface **usb_dev, unsigned char brightness, int side) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + 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: + report = razer_chroma_extended_matrix_brightness(VARSTORE, side, brightness); + break; + + case USB_DEVICE_ID_RAZER_NAGA_LEFT_HANDED_2020: + case USB_DEVICE_ID_RAZER_MAMBA_ELITE: + report = razer_chroma_extended_matrix_brightness(VARSTORE, side, brightness); + report.transaction_id.id = 0x1f; + break; + + default: + report = razer_chroma_standard_set_led_brightness(VARSTORE, side, brightness); + break; + } + + razer_send_payload(usb_dev, &report); +} + +/** + * Read device file "left_led_brightness" + */ +ushort razer_attr_read_left_led_brightness(IOUSBDeviceInterface **usb_dev) +{ + return razer_attr_read_side_led_brightness(usb_dev, LEFT_SIDE_LED); +} + +/** + * Write device file "left_led_brightness" + */ +void razer_attr_write_left_led_brightness(IOUSBDeviceInterface **usb_dev, unsigned char brightness) +{ + return razer_attr_write_side_led_brightness(usb_dev, brightness, LEFT_SIDE_LED); +} + +/** + * Read device file "right_led_brightness" + */ +ushort razer_attr_read_right_led_brightness(IOUSBDeviceInterface **usb_dev) +{ + return razer_attr_read_side_led_brightness(usb_dev, RIGHT_SIDE_LED); +} + +/** + * Write device file "right_led_brightness" + */ +void razer_attr_write_right_led_brightness(IOUSBDeviceInterface **usb_dev, unsigned char brightness) +{ + return razer_attr_write_side_led_brightness(usb_dev, brightness, RIGHT_SIDE_LED); +} diff --git a/src/lib/razermousedock_driver.c b/src/lib/razermousedock_driver.c new file mode 100644 index 0000000..7545a54 --- /dev/null +++ b/src/lib/razermousedock_driver.c @@ -0,0 +1,242 @@ +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to Terry Cain <[email protected]> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "razermousedock_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/** + * Send report to the dock + */ +static int razer_get_report(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report, struct razer_report *response_report) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch (product) { + // These devices require longer waits to read their firmware, serial, and other setting values + case USB_DEVICE_ID_RAZER_MOUSE_CHARGING_DOCK: + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_MOUSE_DOCK_WAIT_MIN_US); + break; + + default: + return -1; + } +} + +/** + * Function to send to device, get response, and actually check the response + */ +static struct razer_report razer_send_payload(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report) +{ + IOReturn retval = -1; + + struct razer_report response_report = {0}; + + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(usb_dev, request_report, &response_report); + + 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) { + //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 { + printf("Invalid Report Length (mousedock)\n"); + } + + return response_report; +} + +/** + * Write device file "mode_static" + * + * Static effect mode is activated whenever the file is written to with 3 bytes + */ +ssize_t razer_mouse_dock_attr_write_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch (product) { + case USB_DEVICE_ID_RAZER_MOUSE_CHARGING_DOCK: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + break; + + default: + printf("razerdock: logo_mode_static not supported for this model\n"); + break; + } + + report.transaction_id.id = 0x3F; + + razer_send_payload(usb_dev, &report); + + } else { + printf("razerdock: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + + +/** + * Write device file "mode_static" + * + * ** NOSTORE version for efficiency in custom lighting configurations + * + * Static effect mode is activated whenever the file is written to with 3 bytes + */ +ssize_t razer_mouse_dock_attr_write_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch (product) { + case USB_DEVICE_ID_RAZER_MOUSE_CHARGING_DOCK: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, ZERO_LED, (struct razer_rgb*) & buf[0]); + break; + + default: + printf("razerdock: logo_mode_static not supported for this model\n"); + break; + } + + report.transaction_id.id = 0x3F; + + razer_send_payload(usb_dev, &report); + + } else { + printf("razerdock: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + + +/** + * Write device file "logo_mode_spectrum" (for extended mouse matrix effects) + * + * Spectrum effect mode is activated whenever the file is written to + */ +ssize_t razer_mouse_dock_attr_write_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_MOUSE_CHARGING_DOCK: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + break; + + default: + printf("razerdock: logo_mode_spectrum not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} + + +/** + * Write device file "logo_mode_breath" (for extended mouse matrix effects) + * + * Sets breathing mode by writing 1, 3 or 6 bytes + */ +ssize_t razer_mouse_dock_attr_write_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_MOUSE_CHARGING_DOCK: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = 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 + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + break; + } + break; + } + + report.transaction_id.id = 0x3f; + + razer_send_payload(usb_dev, &report); + return count; +} + + +/** + * Write device file "logo_mode_none" (for extended mouse matrix effects) + * + * No effect is activated whenever this file is written to + */ +ssize_t razer_mouse_dock_attr_write_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_MOUSE_CHARGING_DOCK: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + break; + + default: + printf("razerdock: logo_mode_none not supported for this model\n"); + return count; + } + + razer_send_payload(usb_dev, &report); + return count; +} diff --git a/src/lib/razermousemat_driver.c b/src/lib/razermousemat_driver.c new file mode 100644 index 0000000..430c822 --- /dev/null +++ b/src/lib/razermousemat_driver.c @@ -0,0 +1,333 @@ +/* + * 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 + * + * Should you need to contact me, the author, you can do so by + * e-mail - mail your message to Terry Cain <[email protected]> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "razermousemat_driver.h" +#include "razercommon.h" +#include "razerchromacommon.h" + +/** + * Send report to the mouse mat + */ +static int razer_get_report(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report, struct razer_report *response_report) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + return razer_get_usb_response(usb_dev, 0x00, request_report, 0x00, response_report, RAZER_MOUSEMAT_WAIT_MIN_US); +} + +/** + * Function to send to device, get response, and actually check the response + */ +static struct razer_report razer_send_payload(IOUSBDeviceInterface **usb_dev, struct razer_report *request_report) +{ + IOReturn retval = -1; + + struct razer_report response_report = {0}; + + request_report->crc = razer_calculate_crc(request_report); + + retval = razer_get_report(usb_dev, request_report, &response_report); + + 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 (mousemat)\n"); + } else if (response_report.status == RAZER_CMD_BUSY) { + //printf("Device is busy (mousemat)\n"); + } else if (response_report.status == RAZER_CMD_FAILURE) { + printf("Command failed (mousemat)\n"); + } else if (response_report.status == RAZER_CMD_NOT_SUPPORTED) { + printf("Command not supported (mousemat)\n"); + } else if (response_report.status == RAZER_CMD_TIMEOUT) { + printf("Command timed out (mousemat)\n"); + } + } else { + printf("Invalid Report Length (mousemat)\n"); + } + + return response_report; +} + +/** + * Write device file "mode_none" + * + * No effect is activated whenever this file is written to + */ +ssize_t razer_mouse_mat_attr_write_mode_none(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + 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: + report = razer_chroma_extended_matrix_effect_none(VARSTORE, ZERO_LED); + break; + + default: + report = razer_chroma_standard_matrix_effect_none(VARSTORE, BACKLIGHT_LED); + break; + } + + razer_send_payload(usb_dev, &report); + + 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 + */ +ssize_t razer_mouse_mat_attr_write_mode_wave(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + unsigned char direction = (unsigned char)strtol(buf, NULL, 10); + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + report = razer_chroma_extended_matrix_effect_wave(VARSTORE, ZERO_LED, direction, 0x28); + break; + + default: + report = razer_chroma_standard_matrix_effect_wave(VARSTORE, BACKLIGHT_LED, direction); + break; + } + + razer_send_payload(usb_dev, &report); + return count; +} + +/** + * Write device file "mode_breath" + */ +ssize_t razer_mouse_mat_attr_write_mode_breath(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_extended_matrix_effect_breathing_single(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + case 6: // Dual colour mode + report = 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 + report = razer_chroma_extended_matrix_effect_breathing_random(VARSTORE, ZERO_LED); + break; + } + break; + + default: + switch(count) { + case 3: // Single colour mode + report = razer_chroma_standard_matrix_effect_breathing_single(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + break; + + case 6: // Dual colour mode + report = razer_chroma_standard_matrix_effect_breathing_dual(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0], (struct razer_rgb*)&buf[3]); + break; + + default: // "Random" colour mode + report = razer_chroma_standard_matrix_effect_breathing_random(VARSTORE, BACKLIGHT_LED); + break; + } + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +/** + * Write device file "mode_static" + * + * Set the mousemat to static mode when 3 RGB bytes are written + */ +ssize_t razer_mouse_mat_attr_write_mode_static(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + report = razer_chroma_extended_matrix_effect_static(VARSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + default: + report = razer_chroma_standard_matrix_effect_static(VARSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + break; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermousemat: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +/** + * Write device file "mode_static" + * + * ** NOSTORE version for efficiency in custom lighting configurations + * + * Set the mousemat to static mode when 3 RGB bytes are written + */ +ssize_t razer_mouse_mat_attr_write_mode_static_no_store(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + if(count == 3) { + switch(product) { + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + report = razer_chroma_extended_matrix_effect_static(NOSTORE, ZERO_LED, (struct razer_rgb *)&buf[0]); + break; + + default: + report = razer_chroma_standard_matrix_effect_static(NOSTORE, BACKLIGHT_LED, (struct razer_rgb*)&buf[0]); + break; + } + + razer_send_payload(usb_dev, &report); + } else { + printf("razermousemat: Static mode only accepts RGB (3byte)\n"); + } + + return count; +} + +ssize_t razer_mouse_mat_attr_write_set_brightness(IOUSBDeviceInterface **usb_dev, ushort brightness, size_t count) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + struct razer_report report = {0}; + + switch (product) { + 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: + report = razer_chroma_extended_matrix_brightness(VARSTORE, ZERO_LED, brightness); + break; + + default: + printf("razermousemat: Unknown device\n"); + break; + } + + razer_send_payload(usb_dev, &report); + + return count; +} + +ushort razer_mouse_mat_attr_read_set_brightness(IOUSBDeviceInterface **usb_dev) +{ + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + struct razer_report report = razer_chroma_standard_get_led_brightness(VARSTORE, BACKLIGHT_LED); + struct razer_report response = {0}; + unsigned char brightness = 0; + + switch (product) { + 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: + brightness = 0xff; // Unfortunately, we can't read the brightness from the device directly. return dummy value. + break; + + default: + response = razer_send_payload(usb_dev, &report); + brightness = response.arguments[2]; + break; + } + brightness = round(brightness / 2.55); + return brightness; +} + +/** + * Write device file "mode_spectrum" + * + * Specrum effect mode is activated whenever the file is written to + */ +ssize_t razer_mouse_mat_attr_write_mode_spectrum(IOUSBDeviceInterface **usb_dev, const char *buf, size_t count) +{ + struct razer_report report = {0}; + + UInt16 product = -1; + (*usb_dev)->GetDeviceProduct(usb_dev, &product); + + switch(product) { + case USB_DEVICE_ID_RAZER_FIREFLY_V2: + case USB_DEVICE_ID_RAZER_FIREFLY_HYPERFLUX: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA: + case USB_DEVICE_ID_RAZER_GOLIATHUS_CHROMA_EXTENDED: + report = razer_chroma_extended_matrix_effect_spectrum(VARSTORE, ZERO_LED); + break; + + default: + report = razer_chroma_standard_matrix_effect_spectrum(VARSTORE, BACKLIGHT_LED); + break; + } + + razer_send_payload(usb_dev, &report); + return count; +}
\ No newline at end of file |
