1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147 |
- /*
- * Lowlevel hardware access for the
- * Razer Synapse wire protocol
- *
- * Important notice:
- * This hardware driver is based on reverse engineering, only.
- *
- * Copyright (C) 2012 Michael Buesch <m@bues.ch>
- *
- * 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.
- */
- #include "librazer.h"
- #include "synapse.h"
- #include "razer_private.h"
- #include "util.h"
- #include "buttonmapping.h"
- enum synapse_constants {
- SYNAPSE_NR_PROFILES = 5,
- SYNAPSE_NR_DPIMAPPINGS = 5,
- SYNAPSE_NR_AXES = 3,
- SYNAPSE_NR_LEDS = 2,
- SYNAPSE_SERIAL_MAX_LEN = 32,
- SYNAPSE_PROFNAME_MAX_LEN = 20,
- };
- enum synapse_phys_button {
- /* Physical button IDs */
- SYNAPSE_PHYSBUT_LEFT = 0x01, /* Left button */
- SYNAPSE_PHYSBUT_RIGHT, /* Right button */
- SYNAPSE_PHYSBUT_MIDDLE, /* Middle button */
- SYNAPSE_PHYSBUT_LFRONT, /* Left side, front button */
- SYNAPSE_PHYSBUT_LREAR, /* Left side, rear button */
- SYNAPSE_PHYSBUT_RFRONT, /* Right side, front button */
- SYNAPSE_PHYSBUT_RREAR, /* Right side, rear button */
- SYNAPSE_PHYSBUT_TFRONT, /* Top side, front button */
- SYNAPSE_PHYSBUT_TREAR, /* Top side, rear button */
- SYNAPSE_PHYSBUT_SCROLLUP, /* Scroll wheel up */
- SYNAPSE_PHYSBUT_SCROLLDWN, /* Scroll wheel down */
- NR_SYNAPSE_PHYSBUT = 11, /* Number of physical buttons */
- };
- struct synapse_request {
- uint8_t magic;
- uint8_t flags;
- uint8_t rw;
- uint8_t command;
- uint8_t request;
- uint8_t _padding[3];
- uint8_t payload[80];
- le16_t checksum;
- } _packed;
- #define SYNAPSE_REQ_MAGIC 0x01
- #define SYNAPSE_REQ_FLG_TRANSOK 0x02
- #define SYNAPSE_REQ_READ 0x01
- #define SYNAPSE_REQ_WRITE 0x00
- struct synapse_request_devinfo {
- uint8_t serial[SYNAPSE_SERIAL_MAX_LEN];
- uint8_t fwver[2];
- } _packed;
- struct synapse_request_globconfig {
- uint8_t profile;
- uint8_t freq;
- uint8_t dpisel;
- uint8_t dpival0;
- uint8_t dpival1;
- } _packed;
- struct synapse_request_profname {
- uint8_t profile;
- union {
- uint8_t name_raw[SYNAPSE_PROFNAME_MAX_LEN * 2]; /* UTF-16-LE */
- le16_t name_le16[SYNAPSE_PROFNAME_MAX_LEN];
- } _packed;
- } _packed;
- struct synapse_one_dpimapping {
- uint8_t dpival0;
- uint8_t dpival1;
- } _packed;
- struct synapse_led_color {
- uint8_t r;
- uint8_t g;
- uint8_t b;
- uint8_t padding;
- } _packed;
- #define SYNAPSE_LED_COLOR_PADDING 0xFF
- struct synapse_request_hwconfig {
- uint8_t profile;
- uint8_t leds;
- uint8_t dpisel;
- uint8_t nr_dpimappings;
- struct synapse_one_dpimapping dpimappings[SYNAPSE_NR_DPIMAPPINGS];
- uint8_t _padding[6];
- uint8_t buttonmap[4 * NR_SYNAPSE_PHYSBUT];
- struct synapse_led_color led_colors[SYNAPSE_NR_LEDS];
- } _packed;
- struct synapse_buttons {
- struct razer_buttonmapping mapping[NR_SYNAPSE_PHYSBUT];
- };
- struct synapse_prof_name {
- razer_utf16_t name[SYNAPSE_PROFNAME_MAX_LEN + 1];
- };
- struct synapse_led_name {
- char name[32];
- };
- struct razer_synapse {
- struct razer_mouse *m;
- void *drv_data;
- /* Feature selection bits */
- unsigned int features;
- /* Firmware version */
- uint16_t fw_version;
- /* Device serial number */
- char serial[SYNAPSE_SERIAL_MAX_LEN + 1];
- /* LED names */
- struct synapse_led_name led_names[SYNAPSE_NR_LEDS];
- /* The currently set LED states. */
- enum razer_led_state led_states[SYNAPSE_NR_PROFILES][SYNAPSE_NR_LEDS];
- /* LED colors */
- struct razer_rgb_color led_colors[SYNAPSE_NR_PROFILES][SYNAPSE_NR_LEDS];
- /* The active profile. */
- struct razer_mouse_profile *cur_profile;
- /* Profile configuration (one per profile). */
- struct razer_mouse_profile profiles[SYNAPSE_NR_PROFILES];
- /* Profile names */
- struct synapse_prof_name profile_names[SYNAPSE_NR_PROFILES];
- /* Supported mouse axes */
- struct razer_axis axes[SYNAPSE_NR_AXES];
- /* The active DPI mapping; per profile. */
- struct razer_mouse_dpimapping *cur_dpimapping[SYNAPSE_NR_PROFILES];
- /* The possible DPI mappings. */
- struct razer_mouse_dpimapping dpimappings[SYNAPSE_NR_PROFILES][SYNAPSE_NR_DPIMAPPINGS];
- /* The active scan frequency. */
- enum razer_mouse_freq cur_freq;
- /* The active button mapping; per profile. */
- struct synapse_buttons buttons[SYNAPSE_NR_PROFILES];
- bool commit_pending;
- };
- /* A list of physical buttons on the device. */
- static struct razer_button synapse_physical_buttons[] = {
- { .id = SYNAPSE_PHYSBUT_LEFT, .name = "Leftclick", },
- { .id = SYNAPSE_PHYSBUT_RIGHT, .name = "Rightclick", },
- { .id = SYNAPSE_PHYSBUT_MIDDLE, .name = "Middleclick", },
- { .id = SYNAPSE_PHYSBUT_LFRONT, .name = "Leftside front", },
- { .id = SYNAPSE_PHYSBUT_LREAR, .name = "Leftside rear", },
- { .id = SYNAPSE_PHYSBUT_RFRONT, .name = "Rightside front", },
- { .id = SYNAPSE_PHYSBUT_RREAR, .name = "Rightside rear", },
- { .id = SYNAPSE_PHYSBUT_TFRONT, .name = "Top front", },
- { .id = SYNAPSE_PHYSBUT_TREAR, .name = "Top rear", },
- { .id = SYNAPSE_PHYSBUT_SCROLLUP, .name = "Scroll up", },
- { .id = SYNAPSE_PHYSBUT_SCROLLDWN, .name = "Scroll down", },
- };
- /* A list of possible button functions. */
- static struct razer_button_function synapse_button_functions[] = {
- BUTTONFUNC_LEFT,
- BUTTONFUNC_RIGHT,
- BUTTONFUNC_MIDDLE,
- BUTTONFUNC_PROFDOWN,
- BUTTONFUNC_PROFUP,
- BUTTONFUNC_DPIUP,
- BUTTONFUNC_DPIDOWN,
- BUTTONFUNC_DPI1,
- BUTTONFUNC_DPI2,
- BUTTONFUNC_DPI3,
- BUTTONFUNC_DPI4,
- BUTTONFUNC_DPI5,
- BUTTONFUNC_WIN5,
- BUTTONFUNC_WIN4,
- BUTTONFUNC_SCROLLUP,
- BUTTONFUNC_SCROLLDWN,
- };
- /* requests:
- * description: command, request / payload
- * ==================================================
- *
- * get device info: 02, 01
- * ->reply: 02, 22 / struct synapse_request_devinfo
- *
- * get global config: 05, 01 or
- * 05, 00
- * ->reply: 05, 05 / struct synapse_request_globconfig
- *
- * set global config: 05, 05
- *
- * get prof name: 22, 01 / profnr
- * ->reply: 22, 29 / struct synapse_request_profname
- *
- * set prof name: 22, 29 / struct synapse_request_profile
- *
- * get hwconfig: 06, 01 / profnr
- * ->reply: 06, 38 / struct synapse_request_hwconfig
- *
- * set hwconfig: 06, 48 / struct synapse_request_hwconfig
- *
- * get ???: 08, 00
- * ->reply: 08, 04 / all zero
- */
- static le16_t synapse_checksum(const struct synapse_request *req)
- {
- uint16_t checksum;
- checksum = razer_xor8_checksum((const uint8_t *)req + 2,
- sizeof(*req) - 4);
- if (!(req->flags & SYNAPSE_REQ_FLG_TRANSOK))
- checksum |= 0x100;
- return cpu_to_le16(checksum);
- }
- static int synapse_usb_write(struct razer_synapse *s,
- int request, int command, int index,
- void *buf, size_t size)
- {
- int err;
- err = libusb_control_transfer(
- s->m->usb_ctx->h,
- LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS |
- LIBUSB_RECIPIENT_INTERFACE,
- request, command, index,
- buf, size,
- RAZER_USB_TIMEOUT);
- if (err < 0 || (size_t)err != size) {
- razer_error("synapse: usb_write failed\n");
- return -EIO;
- }
- razer_msleep(5);
- return 0;
- }
- static int synapse_usb_read(struct razer_synapse *s,
- int request, int command, int index,
- void *buf, size_t size)
- {
- int err;
- err = libusb_control_transfer(
- s->m->usb_ctx->h,
- LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS |
- LIBUSB_RECIPIENT_INTERFACE,
- request, command, index,
- buf, size,
- RAZER_USB_TIMEOUT);
- if (err < 0 || (size_t)err != size) {
- razer_error("synapse: usb_read failed\n");
- return -EIO;
- }
- razer_msleep(5);
- return 0;
- }
- static int synapse_request_send(struct razer_synapse *s,
- const struct synapse_request *_req)
- {
- struct synapse_request req = *_req;
- req.magic = SYNAPSE_REQ_MAGIC;
- req.checksum = synapse_checksum(&req);
- // razer_dump("WR", &req, sizeof(req));
- return synapse_usb_write(s, LIBUSB_REQUEST_SET_CONFIGURATION,
- 0x300, 0, &req, sizeof(req));
- }
- static int synapse_request_receive(struct razer_synapse *s,
- struct synapse_request *req,
- bool do_checksum)
- {
- le16_t checksum;
- int err;
- memset(req, 0, sizeof(*req));
- err = synapse_usb_read(s, LIBUSB_REQUEST_CLEAR_FEATURE,
- 0x300, 0, req, sizeof(*req));
- if (err)
- return err;
- // razer_dump("RD", req, sizeof(*req));
- if (do_checksum) {
- checksum = synapse_checksum(req);
- if (req->checksum != checksum) {
- razer_error("synapse: Received request with invalid "
- "checksum (was 0x%04X, expected 0x%04X)\n",
- le16_to_cpu(req->checksum),
- le16_to_cpu(checksum));
- return -EIO;
- }
- }
- return 0;
- }
- static int synapse_request_write(struct razer_synapse *s,
- uint8_t command, uint8_t request,
- const void *payload, size_t payload_len)
- {
- struct synapse_request req, nullreq;
- int err;
- if (WARN_ON(payload_len > sizeof(req.payload)))
- return -EINVAL;
- memset(&req, 0, sizeof(req));
- req.rw = SYNAPSE_REQ_WRITE;
- req.command = command;
- req.request = request;
- if (payload)
- memcpy(req.payload, payload, payload_len);
- err = synapse_request_send(s, &req);
- if (err)
- return err;
- err = synapse_request_receive(s, &req, 0);
- if (err)
- return err;
- memset(&nullreq, 0, sizeof(nullreq));
- err = synapse_request_send(s, &nullreq);
- if (err)
- return err;
- if (req.magic != SYNAPSE_REQ_MAGIC) {
- razer_error("synapse: Invalid magic on sent request\n");
- return -EIO;
- }
- if (req.rw != SYNAPSE_REQ_WRITE) {
- razer_error("synapse: Invalid rw flag on sent request\n");
- return -EIO;
- }
- if (req.command != command || req.request != request) {
- razer_error("synapse: Invalid command on sent request\n");
- return -EIO;
- }
- return 0;
- }
- static int synapse_request_read(struct razer_synapse *s,
- uint8_t command, uint8_t request,
- void *payload, size_t payload_len)
- {
- struct synapse_request req, nullreq;
- int err;
- if (WARN_ON(payload_len > sizeof(req.payload)))
- return -EINVAL;
- memset(&req, 0, sizeof(req));
- req.rw = SYNAPSE_REQ_READ;
- req.command = command;
- req.request = request;
- if (payload)
- memcpy(req.payload, payload, payload_len);
- err = synapse_request_send(s, &req);
- if (err)
- return err;
- err = synapse_request_receive(s, &req, 0);
- if (err)
- return err;
- memset(&nullreq, 0, sizeof(nullreq));
- err = synapse_request_send(s, &nullreq);
- if (err)
- return err;
- if (payload)
- memcpy(payload, req.payload, payload_len);
- if (req.magic != SYNAPSE_REQ_MAGIC) {
- razer_error("synapse: Invalid magic on received request\n");
- return -EIO;
- }
- if (!(req.flags & SYNAPSE_REQ_FLG_TRANSOK)) {
- razer_error("synapse: Failed to receive request. (TRANSOK flag)\n");
- return -EIO;
- }
- if (req.rw != SYNAPSE_REQ_READ) {
- razer_error("synapse: Invalid rw flag on received request\n");
- return -EIO;
- }
- if (req.command != command) {
- razer_error("synapse: Invalid command on received request\n");
- return -EIO;
- }
- return 0;
- }
- static int synapse_read_config_from_hw(struct razer_synapse *s)
- {
- unsigned int i, j;
- int err;
- struct synapse_request_profname profname;
- struct synapse_request_globconfig globconfig;
- struct synapse_request_hwconfig hwconfig;
- enum razer_mouse_res res_x, res_y;
- /* Get global config */
- memset(&globconfig, 0, sizeof(globconfig));
- err = synapse_request_read(s, 5, 1,
- &globconfig, sizeof(globconfig));
- if (err)
- return err;
- if (globconfig.profile < 1 || globconfig.profile > SYNAPSE_NR_PROFILES) {
- razer_error("synapse: Got invalid profile number: %u\n",
- (unsigned int)globconfig.profile);
- globconfig.profile = 1;
- }
- s->cur_profile = &s->profiles[globconfig.profile - 1];
- switch (globconfig.freq) {
- case 1:
- s->cur_freq = RAZER_MOUSE_FREQ_1000HZ;
- break;
- case 2:
- s->cur_freq = RAZER_MOUSE_FREQ_500HZ;
- break;
- case 8:
- s->cur_freq = RAZER_MOUSE_FREQ_125HZ;
- break;
- default:
- razer_error("synapse: "
- "Read invalid frequency value from device (%u)\n",
- globconfig.freq);
- s->cur_freq = RAZER_MOUSE_FREQ_125HZ;
- }
- /* Get the profile names */
- for (i = 0; i < SYNAPSE_NR_PROFILES; i++) {
- memset(&profname, 0, sizeof(profname));
- profname.profile = i + 1;
- err = synapse_request_read(s, 0x22, 1,
- &profname, sizeof(profname));
- if (err)
- return err;
- memset(&s->profile_names[i], 0, sizeof(s->profile_names[i]));
- for (j = 0; j < SYNAPSE_PROFNAME_MAX_LEN; j++) {
- s->profile_names[i].name[j] = profname.name_raw[j * 2 + 0];
- s->profile_names[i].name[j] |= (uint16_t)profname.name_raw[j * 2 + 1] << 8;
- }
- }
- /* Get the profile configs */
- for (i = 0; i < SYNAPSE_NR_PROFILES; i++) {
- memset(&hwconfig, 0, sizeof(hwconfig));
- hwconfig.profile = i + 1;
- err = synapse_request_read(s, 6, 1,
- &hwconfig, sizeof(hwconfig));
- if (err)
- return err;
- if (hwconfig.profile != i + 1) {
- razer_error("synapse: Failed to read hw config (%u vs %u)\n",
- hwconfig.profile, i + 1);
- hwconfig.profile = i + 1;
- }
- for (j = 0; j < SYNAPSE_NR_LEDS; j++)
- s->led_states[i][j] = !!(hwconfig.leds & (1 << j));
- if (hwconfig.nr_dpimappings < 1 ||
- hwconfig.nr_dpimappings > SYNAPSE_NR_DPIMAPPINGS) {
- razer_error("synapse: Got invalid nr_dpimappings: %u\n",
- hwconfig.nr_dpimappings);
- hwconfig.nr_dpimappings = SYNAPSE_NR_DPIMAPPINGS;
- }
- if (hwconfig.dpisel < 1 || hwconfig.dpisel > SYNAPSE_NR_DPIMAPPINGS ||
- hwconfig.dpisel > hwconfig.nr_dpimappings) {
- razer_error("synapse: Got invalid DPI selection: %u\n",
- hwconfig.dpisel);
- hwconfig.dpisel = 1;
- }
- s->cur_dpimapping[i] = &s->dpimappings[i][hwconfig.dpisel - 1];
- for (j = 0; j < SYNAPSE_NR_DPIMAPPINGS; j++) {
- if (j + 1 > hwconfig.nr_dpimappings) {
- res_x = RAZER_MOUSE_RES_5600DPI;
- res_y = res_x;
- } else {
- res_x = ((hwconfig.dpimappings[j].dpival0 / 4) + 1) * 100;
- res_y = ((hwconfig.dpimappings[j].dpival1 / 4) + 1) * 100;
- }
- s->dpimappings[i][j].res[RAZER_DIM_X] = res_x;
- s->dpimappings[i][j].res[RAZER_DIM_Y] = res_y;
- }
- err = razer_parse_buttonmap(hwconfig.buttonmap, sizeof(hwconfig.buttonmap),
- s->buttons[i].mapping,
- ARRAY_SIZE(s->buttons[i].mapping), 2);
- if (err)
- return err;
- for (j = 0; j < SYNAPSE_NR_LEDS; j++) {
- s->led_colors[i][j].r = hwconfig.led_colors[j].r;
- s->led_colors[i][j].g = hwconfig.led_colors[j].g;
- s->led_colors[i][j].b = hwconfig.led_colors[j].b;
- s->led_colors[i][j].valid = !!(s->features & RAZER_SYNFEAT_RGBLEDS);
- }
- }
- return 0;
- }
- static int synapse_read_devinfo(struct razer_synapse *s)
- {
- struct synapse_request_devinfo devinfo;
- int err;
- s->fw_version = 0;
- memset(s->serial, 0, sizeof(s->serial));
- memset(&devinfo, 0, sizeof(devinfo));
- err = synapse_request_read(s, 2, 1,
- &devinfo, sizeof(devinfo));
- if (err)
- return -EIO;
- s->fw_version = ((uint16_t)(devinfo.fwver[0]) << 8) |
- devinfo.fwver[1];
- memcpy(s->serial, devinfo.serial, SYNAPSE_SERIAL_MAX_LEN);
- return 0;
- }
- static int synapse_get_fw_version(struct razer_mouse *m)
- {
- struct razer_synapse *s = m->drv_data;
- return s->fw_version;
- }
- static int synapse_do_commit(struct razer_synapse *s)
- {
- struct synapse_request_profname profname;
- struct synapse_request_globconfig globconfig;
- struct synapse_request_hwconfig hwconfig;
- int err;
- unsigned int i, j;
- /* Commit profile configs */
- for (i = 0; i < SYNAPSE_NR_PROFILES; i++) {
- memset(&hwconfig, 0, sizeof(hwconfig));
- hwconfig.profile = i + 1;
- hwconfig.leds = 0x04; /* Bit 2 is always set */
- for (j = 0; j < SYNAPSE_NR_LEDS; j++) {
- if (s->led_states[i][j])
- hwconfig.leds |= (1 << j);
- }
- hwconfig.dpisel = (s->cur_dpimapping[i]->nr % 10) + 1;
- hwconfig.nr_dpimappings = SYNAPSE_NR_DPIMAPPINGS;
- for (j = 0; j < SYNAPSE_NR_DPIMAPPINGS; j++) {
- hwconfig.dpimappings[j].dpival0 = ((s->dpimappings[i][j].res[RAZER_DIM_X] / 100) - 1) * 4;
- hwconfig.dpimappings[j].dpival1 = ((s->dpimappings[i][j].res[RAZER_DIM_Y] / 100) - 1) * 4;
- }
- err = razer_create_buttonmap(hwconfig.buttonmap, sizeof(hwconfig.buttonmap),
- s->buttons[i].mapping,
- ARRAY_SIZE(s->buttons[i].mapping), 2);
- if (err)
- return err;
- if (s->features & RAZER_SYNFEAT_RGBLEDS) {
- for (j = 0; j < SYNAPSE_NR_LEDS; j++) {
- hwconfig.led_colors[j].padding = SYNAPSE_LED_COLOR_PADDING;
- hwconfig.led_colors[j].r = s->led_colors[i][j].r;
- hwconfig.led_colors[j].g = s->led_colors[i][j].g;
- hwconfig.led_colors[j].b = s->led_colors[i][j].b;
- }
- }
- err = synapse_request_write(s, 6, 0x48,
- &hwconfig, sizeof(hwconfig));
- if (err)
- return err;
- }
- /* Commit profile names */
- for (i = 0; i < SYNAPSE_NR_PROFILES; i++) {
- memset(&profname, 0, sizeof(profname));
- profname.profile = i + 1;
- for (j = 0; j < SYNAPSE_PROFNAME_MAX_LEN; j++) {
- le16_t c = cpu_to_le16(s->profile_names[i].name[j]);
- profname.name_le16[j] = c;
- }
- err = synapse_request_write(s, 0x22, 0x29,
- &profname, sizeof(profname));
- if (err)
- return err;
- }
- /* Commit global config */
- memset(&globconfig, 0, sizeof(globconfig));
- globconfig.profile = s->cur_profile->nr + 1;
- switch (s->cur_freq) {
- default:
- case RAZER_MOUSE_FREQ_1000HZ:
- globconfig.freq = 1;
- break;
- case RAZER_MOUSE_FREQ_500HZ:
- globconfig.freq = 2;
- break;
- case RAZER_MOUSE_FREQ_125HZ:
- globconfig.freq = 8;
- break;
- }
- globconfig.dpisel = (s->cur_dpimapping[s->cur_profile->nr]->nr % 10) + 1;
- globconfig.dpival0 = ((s->cur_dpimapping[s->cur_profile->nr]->res[RAZER_DIM_X] / 100) - 1) * 4;
- globconfig.dpival1 = ((s->cur_dpimapping[s->cur_profile->nr]->res[RAZER_DIM_Y] / 100) - 1) * 4;
- err = synapse_request_write(s, 5, 5,
- &globconfig, sizeof(globconfig));
- if (err)
- return err;
- return 0;
- }
- static int synapse_commit(struct razer_mouse *m, int force)
- {
- struct razer_synapse *s = m->drv_data;
- int err = 0;
- if (!m->claim_count)
- return -EBUSY;
- if (s->commit_pending || force) {
- err = synapse_do_commit(s);
- if (!err)
- s->commit_pending = 0;
- }
- return err;
- }
- static enum razer_mouse_freq synapse_global_get_freq(struct razer_mouse *m)
- {
- struct razer_synapse *s = m->drv_data;
- return s->cur_freq;
- }
- static int synapse_global_set_freq(struct razer_mouse *m,
- enum razer_mouse_freq freq)
- {
- struct razer_synapse *s = m->drv_data;
- if (!s->m->claim_count)
- return -EBUSY;
- s->cur_freq = freq;
- s->commit_pending = 1;
- return 0;
- }
- static const razer_utf16_t * synapse_profile_get_name(struct razer_mouse_profile *p)
- {
- struct razer_mouse *m = p->mouse;
- struct razer_synapse *s = m->drv_data;
- if (p->nr >= SYNAPSE_NR_PROFILES)
- return NULL;
- return s->profile_names[p->nr].name;
- }
- static int synapse_profile_set_name(struct razer_mouse_profile *p,
- const razer_utf16_t *new_name)
- {
- struct razer_mouse *m = p->mouse;
- struct razer_synapse *s = m->drv_data;
- int err;
- if (p->nr >= SYNAPSE_NR_PROFILES)
- return -EINVAL;
- if (!m->claim_count)
- return -EBUSY;
- err = razer_utf16_cpy(s->profile_names[p->nr].name,
- new_name, SYNAPSE_PROFNAME_MAX_LEN);
- s->commit_pending = 1;
- return err;
- }
- static int synapse_led_toggle(struct razer_led *led,
- enum razer_led_state new_state)
- {
- struct razer_mouse_profile *p = led->u.mouse_prof;
- struct razer_mouse *m = p->mouse;
- struct razer_synapse *s = m->drv_data;
- if (led->id >= SYNAPSE_NR_LEDS)
- return -EINVAL;
- if ((new_state != RAZER_LED_OFF) &&
- (new_state != RAZER_LED_ON))
- return -EINVAL;
- if (p->nr >= SYNAPSE_NR_PROFILES)
- return -EINVAL;
- if (!s->m->claim_count)
- return -EBUSY;
- s->led_states[p->nr][led->id] = new_state;
- s->commit_pending = 1;
- return 0;
- }
- static int synapse_led_change_color(struct razer_led *led,
- const struct razer_rgb_color *new_color)
- {
- struct razer_mouse_profile *p = led->u.mouse_prof;
- struct razer_mouse *m = p->mouse;
- struct razer_synapse *s = m->drv_data;
- if (led->id >= SYNAPSE_NR_LEDS)
- return -EINVAL;
- if (p->nr >= SYNAPSE_NR_PROFILES)
- return -EINVAL;
- if (!s->m->claim_count)
- return -EBUSY;
- s->led_colors[p->nr][led->id] = *new_color;
- s->commit_pending = 1;
- return 0;
- }
- static struct razer_mouse_profile * synapse_get_profiles(struct razer_mouse *m)
- {
- struct razer_synapse *s = m->drv_data;
- return &s->profiles[0];
- }
- static struct razer_mouse_profile * synapse_get_active_profile(struct razer_mouse *m)
- {
- struct razer_synapse *s = m->drv_data;
- return s->cur_profile;
- }
- static int synapse_set_active_profile(struct razer_mouse *m,
- struct razer_mouse_profile *p)
- {
- struct razer_synapse *s = m->drv_data;
- if (!s->m->claim_count)
- return -EBUSY;
- s->cur_profile = p;
- s->commit_pending = 1;
- return 0;
- }
- static int synapse_supported_dpimappings(struct razer_mouse *m,
- struct razer_mouse_dpimapping **res_ptr)
- {
- struct razer_synapse *s = m->drv_data;
- *res_ptr = &s->dpimappings[0][0];
- return SYNAPSE_NR_PROFILES * SYNAPSE_NR_DPIMAPPINGS;
- }
- static struct razer_mouse_dpimapping * synapse_get_dpimapping(struct razer_mouse_profile *p,
- struct razer_axis *axis)
- {
- struct razer_synapse *s = p->mouse->drv_data;
- if (p->nr >= ARRAY_SIZE(s->cur_dpimapping))
- return NULL;
- return s->cur_dpimapping[p->nr];
- }
- static int synapse_set_dpimapping(struct razer_mouse_profile *p,
- struct razer_axis *axis,
- struct razer_mouse_dpimapping *d)
- {
- struct razer_synapse *s = p->mouse->drv_data;
- razer_id_mask_t idmask;
- if (!s->m->claim_count)
- return -EBUSY;
- if (p->nr >= ARRAY_SIZE(s->cur_dpimapping))
- return -EINVAL;
- razer_id_mask_zero(&idmask);
- razer_id_mask_set(&idmask, p->nr);
- if (d->profile_mask != idmask)
- return -EINVAL;
- s->cur_dpimapping[p->nr] = d;
- s->commit_pending = 1;
- return 0;
- }
- static int synapse_dpimapping_modify(struct razer_mouse_dpimapping *d,
- enum razer_dimension dim,
- enum razer_mouse_res res)
- {
- struct razer_synapse *s = d->mouse->drv_data;
- if ((int)dim < 0 || (unsigned int)dim >= ARRAY_SIZE(d->res))
- return -EINVAL;
- if (!s->m->claim_count)
- return -EBUSY;
- d->res[dim] = res;
- s->commit_pending = 1;
- return 0;
- }
- static int synapse_profile_get_leds(struct razer_mouse_profile *p,
- struct razer_led **leds_list)
- {
- struct razer_synapse *s = p->mouse->drv_data;
- struct razer_led *leds[SYNAPSE_NR_LEDS];
- int i;
- if (p->nr >= SYNAPSE_NR_PROFILES)
- return -EINVAL;
- for (i = 0; i < SYNAPSE_NR_LEDS; i++) {
- leds[i] = zalloc(sizeof(struct razer_led));
- if (!leds[i]) {
- for (i--; i >= 0; i--)
- razer_free(leds[i], sizeof(struct razer_led));
- return -ENOMEM;
- }
- }
- for (i = 0; i < SYNAPSE_NR_LEDS; i++) {
- leds[i]->name = s->led_names[i].name;
- leds[i]->id = i;
- leds[i]->state = s->led_states[p->nr][i];
- leds[i]->toggle_state = synapse_led_toggle;
- if (s->features & RAZER_SYNFEAT_RGBLEDS) {
- leds[i]->color = s->led_colors[p->nr][i];
- leds[i]->change_color = synapse_led_change_color;
- }
- leds[i]->u.mouse_prof = &s->profiles[p->nr];
- }
- /* Link the list */
- *leds_list = leds[0];
- for (i = 0; i < SYNAPSE_NR_LEDS; i++)
- leds[i]->next = (i < SYNAPSE_NR_LEDS - 1) ? leds[i + 1] : NULL;
- return SYNAPSE_NR_LEDS;
- }
- static int synapse_supported_axes(struct razer_mouse *m,
- struct razer_axis **axes_list)
- {
- struct razer_synapse *s = m->drv_data;
- *axes_list = s->axes;
- return ARRAY_SIZE(s->axes);
- }
- static int synapse_supported_freqs(struct razer_mouse *m,
- enum razer_mouse_freq **freq_list)
- {
- enum razer_mouse_freq *list;
- const int count = 3;
- list = malloc(sizeof(*list) * count);
- if (!list)
- return -ENOMEM;
- list[0] = RAZER_MOUSE_FREQ_1000HZ;
- list[1] = RAZER_MOUSE_FREQ_500HZ;
- list[2] = RAZER_MOUSE_FREQ_125HZ;
- *freq_list = list;
- return count;
- }
- static int synapse_supported_resolutions(struct razer_mouse *m,
- enum razer_mouse_res **res_list)
- {
- enum razer_mouse_res *list;
- unsigned int i, count = 0, res, step = 0;
- count = 56;
- step = RAZER_MOUSE_RES_100DPI;
- list = malloc(sizeof(*list) * count);
- if (!list)
- return -ENOMEM;
- res = step;
- for (i = 0; i < count; i++) {
- list[i] = res;
- res += step;
- }
- *res_list = list;
- return count;
- }
- static int synapse_supported_buttons(struct razer_mouse *m,
- struct razer_button **res_ptr)
- {
- *res_ptr = synapse_physical_buttons;
- return ARRAY_SIZE(synapse_physical_buttons);
- }
- static int synapse_supported_button_functions(struct razer_mouse *m,
- struct razer_button_function **res_ptr)
- {
- *res_ptr = synapse_button_functions;
- return ARRAY_SIZE(synapse_button_functions);
- }
- static struct razer_button_function * synapse_get_button_function(struct razer_mouse_profile *p,
- struct razer_button *b)
- {
- struct razer_synapse *s = p->mouse->drv_data;
- struct synapse_buttons *buttons;
- if (p->nr > ARRAY_SIZE(s->buttons))
- return NULL;
- buttons = &s->buttons[p->nr];
- return razer_get_buttonfunction_by_button(
- buttons->mapping, ARRAY_SIZE(buttons->mapping),
- synapse_button_functions, ARRAY_SIZE(synapse_button_functions),
- b);
- }
- static int synapse_set_button_function(struct razer_mouse_profile *p,
- struct razer_button *b,
- struct razer_button_function *f)
- {
- struct razer_synapse *s = p->mouse->drv_data;
- struct synapse_buttons *buttons;
- struct razer_buttonmapping *mapping;
- if (!s->m->claim_count)
- return -EBUSY;
- if (p->nr > ARRAY_SIZE(s->buttons))
- return -EINVAL;
- buttons = &s->buttons[p->nr];
- mapping = razer_get_buttonmapping_by_physid(
- buttons->mapping, ARRAY_SIZE(buttons->mapping),
- b->id);
- if (!mapping)
- return -ENODEV;
- mapping->logical = f->id;
- s->commit_pending = 1;
- return 0;
- }
- int razer_synapse_init(struct razer_mouse *m,
- void *drv_data,
- unsigned int features)
- {
- struct razer_synapse *s;
- int i, j, k, err;
- BUILD_BUG_ON(sizeof(struct synapse_request) != 90);
- BUILD_BUG_ON(sizeof(struct synapse_request_devinfo) != 34);
- BUILD_BUG_ON(sizeof(struct synapse_request_globconfig) != 5);
- BUILD_BUG_ON(sizeof(struct synapse_request_profname) != 41);
- BUILD_BUG_ON(sizeof(struct synapse_request_hwconfig) != 72);
- s = zalloc(sizeof(*s));
- if (!s)
- return -ENOMEM;
- m->drv_data = s;
- s->m = m;
- s->drv_data = drv_data;
- s->features = features;
- err = razer_usb_add_used_interface(m->usb_ctx, 0, 0);
- if (err) {
- err = -ENODEV;
- goto err_free;
- }
- for (i = 0; i < SYNAPSE_NR_PROFILES; i++) {
- s->profiles[i].nr = i;
- s->profiles[i].get_leds = synapse_profile_get_leds;
- s->profiles[i].get_name = synapse_profile_get_name;
- s->profiles[i].set_name = synapse_profile_set_name;
- s->profiles[i].get_dpimapping = synapse_get_dpimapping;
- s->profiles[i].set_dpimapping = synapse_set_dpimapping;
- s->profiles[i].get_button_function = synapse_get_button_function;
- s->profiles[i].set_button_function = synapse_set_button_function;
- s->profiles[i].mouse = m;
- }
- razer_init_axes(&s->axes[0],
- "X", 0,
- "Y", 0,
- "Scroll", 0);
- for (i = 0; i < SYNAPSE_NR_PROFILES; i++) {
- for (j = 0; j < SYNAPSE_NR_DPIMAPPINGS; j++) {
- s->dpimappings[i][j].nr = i * 10 + j;
- for (k = 0; k < RAZER_NR_DIMS; k++)
- s->dpimappings[i][j].res[k] = RAZER_MOUSE_RES_UNKNOWN;
- s->dpimappings[i][j].dimension_mask = (1 << RAZER_DIM_X) |
- (1 << RAZER_DIM_Y);
- razer_id_mask_zero(&s->dpimappings[i][j].profile_mask);
- razer_id_mask_set(&s->dpimappings[i][j].profile_mask, i);
- s->dpimappings[i][j].change = synapse_dpimapping_modify;
- s->dpimappings[i][j].mouse = m;
- }
- }
- /* Default LED names */
- razer_synapse_set_led_name(m, 0, "ScrollWheel");
- razer_synapse_set_led_name(m, 1, "GlowingLogo");
- err = m->claim(m);
- if (err) {
- razer_error("synapse: "
- "Failed to initially claim the device\n");
- goto err_free;
- }
- err = synapse_read_devinfo(s);
- if (err) {
- razer_error("synapse: Failed to get firmware version\n");
- goto err_release;
- }
- err = synapse_read_config_from_hw(s);
- if (err) {
- razer_error("synapse: "
- "Failed to read the configuration from hardware\n");
- goto err_release;
- }
- m->get_fw_version = synapse_get_fw_version;
- m->commit = synapse_commit;
- m->global_get_freq = synapse_global_get_freq;
- m->global_set_freq = synapse_global_set_freq;
- m->nr_profiles = SYNAPSE_NR_PROFILES;
- m->get_profiles = synapse_get_profiles;
- m->get_active_profile = synapse_get_active_profile;
- m->set_active_profile = synapse_set_active_profile;
- m->supported_axes = synapse_supported_axes;
- m->supported_resolutions = synapse_supported_resolutions;
- m->supported_freqs = synapse_supported_freqs;
- m->supported_dpimappings = synapse_supported_dpimappings;
- m->supported_buttons = synapse_supported_buttons;
- m->supported_button_functions = synapse_supported_button_functions;
- err = synapse_do_commit(s);
- if (err) {
- razer_error("synapse: Failed to commit initial settings\n");
- goto err_release;
- }
- m->release(m);
- return 0;
- err_release:
- m->release(m);
- err_free:
- razer_free(s, sizeof(*s));
- return err;
- }
- void razer_synapse_exit(struct razer_mouse *m)
- {
- struct razer_synapse *s = m->drv_data;
- razer_free(s, sizeof(*s));
- m->drv_data = NULL;
- }
- void * razer_synapse_get_drv_data(struct razer_mouse *m)
- {
- struct razer_synapse *s = m->drv_data;
- return s->drv_data;
- }
- int razer_synapse_set_led_name(struct razer_mouse *m,
- unsigned int index,
- const char *name)
- {
- struct razer_synapse *s = m->drv_data;
- if (index >= ARRAY_SIZE(s->led_names))
- return -EINVAL;
- razer_strlcpy(s->led_names[index].name, name,
- sizeof(s->led_names[index].name));
- return 0;
- }
- const char * razer_synapse_get_serial(struct razer_mouse *m)
- {
- struct razer_synapse *s = m->drv_data;
- return s->serial;
- }
|