parent
34e4828ee7
commit
356d0b975d
@ -0,0 +1,13 @@ |
|||||||
|
CC=gcc
|
||||||
|
CFLAGS=$(shell pkg-config --cflags libusb-1.0) -O3 -Wall -shared
|
||||||
|
LDFLAGS=$(shell pkg-config --libs libusb-1.0)
|
||||||
|
|
||||||
|
FINAL_ASSETS=$(BUILD_DIR)/drivers/assets/razer-viper_mini.png
|
||||||
|
BUILD_DIR=../../build/
|
||||||
|
|
||||||
|
all: $(BUILD_DIR)/drivers/razer.so $(FINAL_ASSETS) |
||||||
|
|
||||||
|
$(BUILD_DIR)/drivers/razer.so: razer.c | $(BUILD_DIR)/drivers/ |
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
$(BUILD_DIR)/drivers/assets/%.png: %.png | $(BUILD_DIR)/drivers/assets |
||||||
|
cp $^ $@
|
After Width: | Height: | Size: 299 KiB |
@ -0,0 +1,106 @@ |
|||||||
|
#include "razer.h" |
||||||
|
|
||||||
|
static uint8_t compute_crc(void* report) |
||||||
|
{ |
||||||
|
uint8_t* r = report; |
||||||
|
|
||||||
|
uint8_t crc = 0; |
||||||
|
for(size_t i = 2; i < REPORT_SIZE - sizeof(report_footer_t); i++) |
||||||
|
{ |
||||||
|
crc ^= r[i]; |
||||||
|
} |
||||||
|
|
||||||
|
return crc; |
||||||
|
} |
||||||
|
|
||||||
|
static int send_command(libusb_device_handle* hand, uint8_t command_class, uint8_t command, uint8_t size, void* report) |
||||||
|
{ |
||||||
|
report_header_t* head = report; |
||||||
|
head->report_size = size; |
||||||
|
head->command_class = command_class; |
||||||
|
head->command_id = command; |
||||||
|
|
||||||
|
report_footer_t* footer = report + REPORT_SIZE - sizeof(report_footer_t); |
||||||
|
footer->crc = compute_crc(report); |
||||||
|
|
||||||
|
// Send command
|
||||||
|
int res = libusb_control_transfer(hand, |
||||||
|
0x21, // request type
|
||||||
|
0x09, // request (SET_REPORT)
|
||||||
|
0x300, // wValue (FEATURE << 8 | REPORT(0))
|
||||||
|
0x0, // wIndex = 0x0 : interface
|
||||||
|
report, |
||||||
|
REPORT_SIZE, // wLength = 90
|
||||||
|
0 /* timeout*/); |
||||||
|
|
||||||
|
if(res <= 0) return res; |
||||||
|
|
||||||
|
// Wait for the mouse to catch the report
|
||||||
|
usleep(100); |
||||||
|
|
||||||
|
// Get response report
|
||||||
|
res = libusb_control_transfer(hand, |
||||||
|
0xa1, // request type
|
||||||
|
0x01, // request (GET_REPORT)
|
||||||
|
0x300, // wValue (FEATURE << 8 | REPORT(0))
|
||||||
|
0x0, // wIndex = 0x0 : interface
|
||||||
|
report, |
||||||
|
REPORT_SIZE, // wLength = 90
|
||||||
|
0); |
||||||
|
|
||||||
|
return res; |
||||||
|
} |
||||||
|
|
||||||
|
void driver_init(void) {} |
||||||
|
|
||||||
|
uint32_t driver_getkey(void) |
||||||
|
{ |
||||||
|
static int count = 0; |
||||||
|
count++; |
||||||
|
|
||||||
|
// Register ALL razer compatible devices
|
||||||
|
uint16_t id = 0; |
||||||
|
switch(count) |
||||||
|
{ |
||||||
|
case 1: |
||||||
|
id = VIPER_MINI_PRODUCT_ID; |
||||||
|
break; |
||||||
|
default: |
||||||
|
id = 0; |
||||||
|
} |
||||||
|
|
||||||
|
if(id == 0) return 0; |
||||||
|
return (VENDOR_ID << 16) | id; |
||||||
|
} |
||||||
|
|
||||||
|
char* driver_get_name(void* handle) |
||||||
|
{ |
||||||
|
libusb_device* dev = handle; |
||||||
|
|
||||||
|
struct libusb_device_descriptor desc; |
||||||
|
libusb_get_device_descriptor(dev, &desc); |
||||||
|
|
||||||
|
switch(desc.idProduct) |
||||||
|
{ |
||||||
|
case VIPER_MINI_PRODUCT_ID: |
||||||
|
return VIPER_MINI_NAME; |
||||||
|
default: |
||||||
|
return "Unknown Razer mice"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
char* driver_get_image(void* handle) |
||||||
|
{ |
||||||
|
libusb_device* dev = handle; |
||||||
|
|
||||||
|
struct libusb_device_descriptor desc; |
||||||
|
libusb_get_device_descriptor(dev, &desc); |
||||||
|
|
||||||
|
switch(desc.idProduct) |
||||||
|
{ |
||||||
|
case VIPER_MINI_PRODUCT_ID: |
||||||
|
return VIPER_MINI_IMAGE; |
||||||
|
default: |
||||||
|
return ""; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,148 @@ |
|||||||
|
#ifndef RAZER_H |
||||||
|
#define RAZER_H |
||||||
|
|
||||||
|
#include <libusb.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <assert.h> |
||||||
|
|
||||||
|
#define VENDOR_ID 0x1532 |
||||||
|
|
||||||
|
#define REPORT_SIZE 90 |
||||||
|
|
||||||
|
/* Devices */ |
||||||
|
#include "viper_mini.h" |
||||||
|
|
||||||
|
typedef struct REPORT_HEADER |
||||||
|
{ |
||||||
|
uint8_t status; |
||||||
|
uint8_t transaction_id; |
||||||
|
|
||||||
|
uint8_t remaining_packets_high; |
||||||
|
uint8_t remaining_packets_low; |
||||||
|
uint8_t protocol_type; // 0x0
|
||||||
|
uint8_t report_size; |
||||||
|
|
||||||
|
uint8_t command_class; |
||||||
|
uint8_t command_id; |
||||||
|
} __attribute__((packed)) report_header_t; |
||||||
|
|
||||||
|
typedef struct REPORT_FOOTER |
||||||
|
{ |
||||||
|
uint8_t crc; // Control, xored bytes of report
|
||||||
|
uint8_t reserved; |
||||||
|
} __attribute__((packed)) report_footer_t; |
||||||
|
|
||||||
|
/* Commands of the BASIC (0x0) class */ |
||||||
|
#define COMMAND_CLASS_BASIC 0x0 |
||||||
|
|
||||||
|
struct REPORT_FIRMWARE_VERSION |
||||||
|
{ |
||||||
|
report_header_t header; |
||||||
|
|
||||||
|
uint8_t version_major; |
||||||
|
uint8_t version_minor; |
||||||
|
|
||||||
|
uint8_t zeros[REPORT_SIZE - sizeof(report_header_t) - sizeof(report_footer_t) - 2]; |
||||||
|
|
||||||
|
report_footer_t footer; |
||||||
|
} __attribute__((packed)); |
||||||
|
#define REPORT_SIZE_FIRMWARE_VERSION 0x2 |
||||||
|
#define COMMAND_REPORT_FIRMWARE_VERSION 0x81 |
||||||
|
static_assert(sizeof(struct REPORT_FIRMWARE_VERSION) == REPORT_SIZE, "REPORT_FIRMWARE_VERSION is not of the right size"); |
||||||
|
|
||||||
|
struct REPORT_POLLING_RATE |
||||||
|
{ |
||||||
|
report_header_t header; |
||||||
|
|
||||||
|
// There is another report for up to 8000Hz polling
|
||||||
|
// 0x01: 1000Hz, 0x2: 500Hz, 0x3: 125Hz
|
||||||
|
uint8_t polling_rate; |
||||||
|
|
||||||
|
uint8_t zeros[REPORT_SIZE - sizeof(report_header_t) - sizeof(report_footer_t) - 1]; |
||||||
|
|
||||||
|
report_footer_t footer; |
||||||
|
} __attribute__((packed)); |
||||||
|
static_assert(sizeof(struct REPORT_POLLING_RATE) == REPORT_SIZE, "REPORT_POLLING_RATE is not of the right size"); |
||||||
|
#define REPORT_SIZE_POLLING_RATE 0x1 |
||||||
|
#define COMMAND_REPORT_POLLING_RATE 0x85 |
||||||
|
|
||||||
|
/* Commands of the DPI (0x4) class */ |
||||||
|
#define COMMAND_CLASS_DPI 0x4 |
||||||
|
|
||||||
|
struct REPORT_DPI |
||||||
|
{ |
||||||
|
report_header_t header; |
||||||
|
|
||||||
|
uint8_t variable_storage; |
||||||
|
uint8_t dpi_x_high; |
||||||
|
uint8_t dpi_x_low; |
||||||
|
uint8_t dpi_y_high; |
||||||
|
uint8_t dpi_y_low; |
||||||
|
uint8_t unknown_0; |
||||||
|
uint8_t unknown_1; |
||||||
|
|
||||||
|
uint8_t zeros[REPORT_SIZE - sizeof(report_header_t) - sizeof(report_footer_t) - 7]; |
||||||
|
|
||||||
|
report_footer_t footer; |
||||||
|
} __attribute__((packed)); |
||||||
|
static_assert(sizeof(struct REPORT_DPI) == REPORT_SIZE, "REPORT_DPI is not of the right size"); |
||||||
|
#define REPORT_SIZE_DPI 0x07 |
||||||
|
#define COMMAND_REPORT_DPI 0x85 |
||||||
|
|
||||||
|
typedef struct DPI_STAGE |
||||||
|
{ |
||||||
|
uint8_t stage_index; |
||||||
|
uint8_t dpi_x_high; |
||||||
|
uint8_t dpi_x_low; |
||||||
|
uint8_t dpi_y_high; |
||||||
|
uint8_t dpi_y_low; |
||||||
|
uint8_t unknown_0; |
||||||
|
uint8_t unknown_1; |
||||||
|
} __attribute__((packed)) dpi_stage_t; |
||||||
|
struct REPORT_DPI_STAGES |
||||||
|
{ |
||||||
|
report_header_t header; |
||||||
|
|
||||||
|
uint8_t variable_storage; |
||||||
|
uint8_t active_dpi_stage; |
||||||
|
uint8_t dpi_stages_count; |
||||||
|
|
||||||
|
dpi_stage_t stages[5]; |
||||||
|
|
||||||
|
uint8_t zeros[REPORT_SIZE - sizeof(report_header_t) - sizeof(report_footer_t) - 38]; |
||||||
|
|
||||||
|
report_footer_t footer; |
||||||
|
} __attribute__((packed)); |
||||||
|
static_assert(sizeof(struct REPORT_DPI_STAGES) == REPORT_SIZE, "REPORT_DPI_STAGES is not of the right size"); |
||||||
|
#define REPORT_SIZE_DPI_STAGES 0x26 |
||||||
|
#define COMMAND_REPORT_DPI_STAGES 0x86 |
||||||
|
|
||||||
|
/* Commands of the BATTERY (0x7) class */ |
||||||
|
#define COMMAND_CLASS_BATTERY 0x7 |
||||||
|
|
||||||
|
struct REPORT_BATTERY_LEVEL |
||||||
|
{ |
||||||
|
report_header_t header; |
||||||
|
|
||||||
|
uint8_t ignored; |
||||||
|
uint8_t battery_level; // 0-255
|
||||||
|
|
||||||
|
report_footer_t footer; |
||||||
|
} __attribute__((packed)); |
||||||
|
#define REPORT_SIZE_BATTERY_LEVEL 0x2 |
||||||
|
#define COMMAND_REPORT_BATTERY_LEVEL 0x80 |
||||||
|
|
||||||
|
struct REPORT_BATTERY_STATUS |
||||||
|
{ |
||||||
|
report_header_t header; |
||||||
|
|
||||||
|
uint8_t ignored; |
||||||
|
uint8_t charging; // 0: not charging, 1:charging
|
||||||
|
|
||||||
|
report_footer_t footer; |
||||||
|
} __attribute__((packed)); |
||||||
|
#define REPORT_SIZE_BATTERY_STATUS 0x2 |
||||||
|
#define COMMAND_REPORT_BATTERY_STATUS 0x84 |
||||||
|
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,8 @@ |
|||||||
|
#ifndef VIPER_MINI_H |
||||||
|
#define VIPER_MINI_H |
||||||
|
|
||||||
|
#define VIPER_MINI_PRODUCT_ID 0x008a |
||||||
|
#define VIPER_MINI_NAME "Viper Mini" |
||||||
|
#define VIPER_MINI_IMAGE "razer-viper_mini.png" |
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue