hw_diamondback_chroma.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. /*
  2. * Lowlevel hardware access for the Razer Diamondback Chroma mouse.
  3. *
  4. * Important notice:
  5. * This hardware driver is based on reverse engineering, only.
  6. *
  7. * Copyright (C) 2015 Konrad Zemek <konrad.zemek@gmail.com>
  8. * Copyright (C) 2016 WANG Haoan <wanghaoan.victor@gmail.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify it under
  11. * the terms of the GNU General Public License as published by the Free Software
  12. * Foundation; either version 2 of the License, or (at your option) any later
  13. * version.
  14. *
  15. * This program is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  17. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  18. * details.
  19. */
  20. #include "hw_diamondback_chroma.h"
  21. #include "razer_private.h"
  22. #include <errno.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <stdint.h>
  26. #include <string.h>
  27. static enum razer_mouse_freq diamondback_chroma_freqs_list[] =
  28. {
  29. RAZER_MOUSE_FREQ_125HZ,
  30. RAZER_MOUSE_FREQ_500HZ,
  31. RAZER_MOUSE_FREQ_1000HZ
  32. };
  33. static enum razer_mouse_res diamondback_chroma_resolution_stages_list[] =
  34. {
  35. RAZER_MOUSE_RES_800DPI,
  36. RAZER_MOUSE_RES_1800DPI,
  37. RAZER_MOUSE_RES_3500DPI,
  38. RAZER_MOUSE_RES_5600DPI,
  39. RAZER_MOUSE_RES_10000DPI,
  40. RAZER_MOUSE_RES_16000DPI
  41. };
  42. #define DIAMONDBACK_CHROMA_DEVICE_NAME "Diamondback Chroma"
  43. #define DIAMONDBACK_CHROMA_LED_NAME "Basic"
  44. enum diamondback_chroma_led_mode
  45. {
  46. DIAMONDBACK_CHROMA_LED_MODE_STATIC = 0x06,
  47. DIAMONDBACK_CHROMA_LED_MODE_BREATHING = 0x0301, // 0x0302 is breathing with 2 different colors
  48. DIAMONDBACK_CHROMA_LED_MODE_SPECTRUM = 0x0400,
  49. DIAMONDBACK_CHROMA_LED_MODE_WAVE = 0x0101, // 0x0102 is waving in a opposite direction
  50. DIAMONDBACK_CHROMA_LED_MODE_REACTION = 0x0203,
  51. DIAMONDBACK_CHROMA_LED_MODE_CUSTOMIZED = 0x0500,
  52. DIAMONDBACK_CHROMA_LED_MODE_CUSTOMIZED_COLOR_INFO = 0x050c, // for further implementation
  53. };
  54. enum diamondback_chroma_led_state
  55. {
  56. DIAMONDBACK_CHROMA_LED_STATE_OFF = 0x00,
  57. DIAMONDBACK_CHROMA_LED_STATE_ON = 0xFF,
  58. };
  59. //for further implementation
  60. enum diamondback_chroma_led_state_option
  61. {
  62. DIAMONDBACK_CHROMA_LED_STATE_OPTION_0 = 0x00,
  63. DIAMONDBACK_CHROMA_LED_STATE_OPTION_1 = 0x01,
  64. DIAMONDBACK_CHROMA_LED_STATE_OPTION_2 = 0x02,
  65. DIAMONDBACK_CHROMA_LED_STATE_OPTION_3 = 0x03,
  66. };
  67. /*
  68. * The 6th byte of Diamondback Chroma's command seems also to be the size of arguments
  69. * (size of arguments to read in case of read operations). It's not necessarily
  70. * so, since some values are slightly off (i.e. bigger than the apparent size
  71. * of the arguments). But when it's in customized mode, there will be 0x32 which is 50 bytes of information
  72. * Experiments suggest that the value given in the 'size' byte does not matter.
  73. * I chose to go with the values used by the Synapse driver.
  74. */
  75. enum diamondback_chroma_request_size
  76. {
  77. DIAMONDBACK_CHROMA_REQUEST_SIZE_INIT = 0x02,
  78. DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_RESOLUTION = 0x07,
  79. DIAMONDBACK_CHROMA_REQUEST_SIZE_GET_FIRMWARE = 0x04,
  80. DIAMONDBACK_CHROMA_REQUEST_SIZE_GET_SERIAL_NO = 0x16,
  81. DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_FREQUENCY = 0x01,
  82. DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_LED_STATE = 0x08,
  83. DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_LED_MODE = 0x08,
  84. DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_LED_COLOR = 0x08,
  85. };
  86. enum diamondback_chroma_request
  87. {
  88. DIAMONDBACK_CHROMA_REQUEST_INIT = 0x0004,
  89. DIAMONDBACK_CHROMA_REQUEST_SET_RESOLUTION = 0x0405,
  90. DIAMONDBACK_CHROMA_REQUEST_GET_FIRMWARE = 0x0087,
  91. DIAMONDBACK_CHROMA_REQUEST_GET_SERIAL_NO = 0x0082,
  92. DIAMONDBACK_CHROMA_REQUEST_SET_FREQUENCY = 0x0005,
  93. DIAMONDBACK_CHROMA_REQUEST_SET_LED_STATE = 0x030a,
  94. DIAMONDBACK_CHROMA_REQUEST_SET_LED_COLOR = 0x030a,
  95. DIAMONDBACK_CHROMA_REQUEST_SET_LED_MODE = 0x030a,
  96. DIAMONDBACK_CHROMA_REQUEST_SET_LED_MODE_CUSTOMIZED = 0x030c, // for further implementation
  97. };
  98. enum diamondback_chroma_constants
  99. {
  100. DIAMONDBACK_CHROMA_MAX_FREQUENCY = RAZER_MOUSE_FREQ_1000HZ,
  101. DIAMONDBACK_CHROMA_MAX_RESOLUTION = RAZER_MOUSE_RES_16000DPI,
  102. DIAMONDBACK_CHROMA_RESOLUTION_STEP = RAZER_MOUSE_RES_100DPI,
  103. DIAMONDBACK_CHROMA_LED_NUM = 1,
  104. DIAMONDBACK_CHROMA_AXES_NUM = 2,
  105. DIAMONDBACK_CHROMA_SUPPORTED_FREQ_NUM = ARRAY_SIZE(diamondback_chroma_freqs_list),
  106. DIAMONDBACK_CHROMA_DPIMAPPINGS_NUM = ARRAY_SIZE(diamondback_chroma_resolution_stages_list),
  107. DIAMONDBACK_CHROMA_USB_SETUP_PACKET_VALUE = 0x300,
  108. DIAMONDBACK_CHROMA_SUCCESS_STATUS = 0x02,
  109. DIAMONDBACK_CHROMA_PACKET_SPACING_MS = 35,
  110. /*
  111. * Experiments suggest that the value in the 'magic' byte of the command
  112. * does not necessarily matter (e.g. the commands work when the 'magic'
  113. * byte equals 0x77). I chose to go with the value used by the Synapse
  114. * driver.
  115. */
  116. DIAMONDBACK_CHROMA_MAGIC_BYTE = 0xFF,
  117. /*
  118. * These specific arg0 bytes are used by the Synapse driver for their
  119. * respective commands. Their value may or may not matter (e.g. matters
  120. * in the case of LED commands, doesn't seem to matter for the
  121. * resolution command).
  122. */
  123. DIAMONDBACK_CHROMA_LED_ARG0 = 0x02,
  124. DIAMONDBACK_CHROMA_INIT_ARG0 = 0x03,
  125. DIAMONDBACK_CHROMA_RESOLUTION_ARG0 = 0x01,
  126. };
  127. struct diamondback_chroma_command
  128. {
  129. uint8_t status;
  130. uint8_t magic;
  131. uint8_t padding0[3];
  132. uint8_t size;
  133. be16_t request;
  134. union
  135. {
  136. uint8_t bvalue[80];
  137. struct
  138. {
  139. uint8_t padding1;
  140. be16_t value[38];
  141. uint8_t padding2;
  142. }_packed;
  143. }_packed;
  144. uint8_t checksum;
  145. uint8_t padding3;
  146. }_packed;
  147. #define DIAMONDBACK_CHROMA_COMMAND_INIT \
  148. (struct diamondback_chroma_command) \
  149. { \
  150. .magic = DIAMONDBACK_CHROMA_MAGIC_BYTE \
  151. }
  152. struct diamondback_chroma_rgb_color
  153. {
  154. uint8_t r;
  155. uint8_t g;
  156. uint8_t b;
  157. };
  158. struct diamondback_chroma_led
  159. {
  160. enum diamondback_chroma_led_mode mode;
  161. enum diamondback_chroma_led_state state;
  162. enum diamondback_chroma_led_state_option option;
  163. struct diamondback_chroma_rgb_color color;
  164. };
  165. struct diamondback_chroma_driver_data
  166. {
  167. struct razer_event_spacing packet_spacing;
  168. struct razer_mouse_profile profile;
  169. struct razer_mouse_dpimapping *current_dpimapping;
  170. enum razer_mouse_freq current_freq;
  171. struct diamondback_chroma_led led;
  172. struct razer_mouse_dpimapping dpimappings[DIAMONDBACK_CHROMA_DPIMAPPINGS_NUM];
  173. struct razer_axis axes[DIAMONDBACK_CHROMA_AXES_NUM];
  174. uint16_t fw_version;
  175. char serial[DIAMONDBACK_CHROMA_REQUEST_SIZE_GET_SERIAL_NO + 1];
  176. };
  177. static uint8_t diamondback_chroma_checksum(struct diamondback_chroma_command *cmd)
  178. {
  179. size_t control_size;
  180. control_size = sizeof(cmd->size) + sizeof(cmd->request);
  181. return razer_xor8_checksum((uint8_t *)&cmd->size, control_size + cmd->size);
  182. }
  183. static int diamondback_chroma_translate_frequency(enum razer_mouse_freq freq)
  184. {
  185. switch (freq) {
  186. case RAZER_MOUSE_FREQ_UNKNOWN:
  187. freq = RAZER_MOUSE_FREQ_500HZ;
  188. /* fallthrough */
  189. case RAZER_MOUSE_FREQ_125HZ:
  190. case RAZER_MOUSE_FREQ_500HZ:
  191. case RAZER_MOUSE_FREQ_1000HZ:
  192. return DIAMONDBACK_CHROMA_MAX_FREQUENCY / freq;
  193. default:
  194. return -EINVAL;
  195. }
  196. }
  197. static int diamondback_chroma_usb_action(struct razer_mouse *m,
  198. enum libusb_endpoint_direction direction,
  199. enum libusb_standard_request request,
  200. uint16_t command,
  201. struct diamondback_chroma_command *cmd)
  202. {
  203. int err;
  204. struct diamondback_chroma_driver_data *drv_data;
  205. drv_data = m->drv_data;
  206. razer_event_spacing_enter(&drv_data->packet_spacing);
  207. err = libusb_control_transfer(m->usb_ctx->h,
  208. direction |
  209. LIBUSB_REQUEST_TYPE_CLASS |
  210. LIBUSB_RECIPIENT_INTERFACE,
  211. request, command, 0,
  212. (unsigned char *)cmd, sizeof(*cmd),
  213. RAZER_USB_TIMEOUT);
  214. razer_event_spacing_leave(&drv_data->packet_spacing);
  215. if (err != sizeof(*cmd)) {
  216. razer_error("razer-diamondback-chroma: "
  217. "USB %s 0x%01X 0x%02X failed with %d\n",
  218. direction == LIBUSB_ENDPOINT_IN ? "read" : "write",
  219. request, command, err);
  220. return err;
  221. }
  222. return 0;
  223. }
  224. static int diamondback_chroma_send_command(struct razer_mouse *m,
  225. struct diamondback_chroma_command *cmd)
  226. {
  227. int err;
  228. uint8_t checksum;
  229. cmd->checksum = diamondback_chroma_checksum(cmd);
  230. err = diamondback_chroma_usb_action(m, LIBUSB_ENDPOINT_OUT,
  231. LIBUSB_REQUEST_SET_CONFIGURATION,
  232. DIAMONDBACK_CHROMA_USB_SETUP_PACKET_VALUE, cmd);
  233. if (err)
  234. return err;
  235. err = diamondback_chroma_usb_action(m, LIBUSB_ENDPOINT_IN,
  236. LIBUSB_REQUEST_CLEAR_FEATURE,
  237. DIAMONDBACK_CHROMA_USB_SETUP_PACKET_VALUE, cmd);
  238. if (err)
  239. return err;
  240. checksum = diamondback_chroma_checksum (cmd);
  241. if (checksum != cmd->checksum) {
  242. razer_error("razer-diamondback-chroma: "
  243. "Command %02X %04X bad response checksum %02X "
  244. "(expected %02X)\n",
  245. cmd->size, be16_to_cpu(cmd->request),
  246. checksum, cmd->checksum);
  247. return -EBADMSG;
  248. }
  249. if (cmd->status != DIAMONDBACK_CHROMA_SUCCESS_STATUS) {
  250. razer_error("razer-diamondback-chroma: "
  251. "Command %02X %04X failed with %02X\n",
  252. cmd->size, be16_to_cpu(cmd->request), cmd->status);
  253. }
  254. return 0;
  255. }
  256. static int diamondback_chroma_send_init_command(struct razer_mouse *m)
  257. {
  258. struct diamondback_chroma_command cmd;
  259. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  260. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_INIT;
  261. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_INIT);
  262. cmd.bvalue[0] = DIAMONDBACK_CHROMA_INIT_ARG0;
  263. return diamondback_chroma_send_command(m, &cmd);
  264. }
  265. static int diamondback_chroma_send_set_resolution_command(struct razer_mouse *m)
  266. {
  267. enum razer_mouse_res res_x, res_y;
  268. struct diamondback_chroma_command cmd;
  269. struct diamondback_chroma_driver_data *drv_data;
  270. drv_data = m->drv_data;
  271. res_x = drv_data->current_dpimapping->res[RAZER_DIM_X];
  272. res_y = drv_data->current_dpimapping->res[RAZER_DIM_Y];
  273. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  274. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_RESOLUTION;
  275. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_SET_RESOLUTION);
  276. cmd.bvalue[0] = DIAMONDBACK_CHROMA_RESOLUTION_ARG0;
  277. cmd.value[0] = cpu_to_be16(res_x);
  278. cmd.value[1] = cpu_to_be16(res_y);
  279. return diamondback_chroma_send_command(m, &cmd);
  280. }
  281. static int diamondback_chroma_send_get_firmware_command(struct razer_mouse *m)
  282. {
  283. int err;
  284. uint8_t fw_major;
  285. uint16_t fw_minor;
  286. struct diamondback_chroma_command cmd;
  287. struct diamondback_chroma_driver_data *drv_data;
  288. drv_data = m->drv_data;
  289. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  290. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_GET_FIRMWARE;
  291. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_GET_FIRMWARE);
  292. err = diamondback_chroma_send_command(m, &cmd);
  293. if (err)
  294. return err;
  295. fw_major = cmd.bvalue[0];
  296. fw_minor = be16_to_cpu(cmd.value[0]);
  297. drv_data->fw_version = (fw_major << 8) | fw_minor;
  298. return 0;
  299. }
  300. static int diamondback_chroma_send_get_serial_no_command(struct razer_mouse *m)
  301. {
  302. int err;
  303. struct diamondback_chroma_command cmd;
  304. struct diamondback_chroma_driver_data *drv_data;
  305. drv_data = m->drv_data;
  306. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  307. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_GET_SERIAL_NO;
  308. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_GET_SERIAL_NO);
  309. err = diamondback_chroma_send_command(m, &cmd);
  310. if (err)
  311. return err;
  312. strncpy(drv_data->serial, (const char *)cmd.bvalue,
  313. DIAMONDBACK_CHROMA_REQUEST_SIZE_GET_SERIAL_NO);
  314. drv_data->serial[DIAMONDBACK_CHROMA_REQUEST_SIZE_GET_SERIAL_NO] = '\0';
  315. return 0;
  316. }
  317. static int diamondback_chroma_send_set_frequency_command(struct razer_mouse *m)
  318. {
  319. int tfreq;
  320. struct diamondback_chroma_command cmd;
  321. struct diamondback_chroma_driver_data *drv_data;
  322. drv_data = m->drv_data;
  323. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  324. tfreq = diamondback_chroma_translate_frequency(drv_data->current_freq);
  325. if (tfreq < 0)
  326. return tfreq;
  327. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_FREQUENCY;
  328. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_SET_FREQUENCY);
  329. cmd.bvalue[0] = tfreq;
  330. return diamondback_chroma_send_command(m, &cmd);
  331. }
  332. static struct diamondback_chroma_led *diamondback_chroma_get_led(struct diamondback_chroma_driver_data *d)
  333. {
  334. return &d->led;
  335. }
  336. static int diamondback_chroma_send_set_led_state_command(struct razer_mouse *m,
  337. struct diamondback_chroma_led *led)
  338. {
  339. struct diamondback_chroma_command cmd;
  340. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  341. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_LED_STATE;
  342. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_SET_LED_STATE);
  343. if (led->mode == DIAMONDBACK_CHROMA_LED_MODE_STATIC) {
  344. cmd.bvalue[0] = led->mode;
  345. cmd.bvalue[1] = led->color.r;
  346. cmd.bvalue[2] = led->color.g;
  347. cmd.bvalue[3] = led->color.b;
  348. } else {
  349. uint16_t tempHex;
  350. uint8_t tempH, tempL;
  351. tempHex = led->mode;
  352. tempH = (uint8_t)((tempHex & 0xFF00) >> 8);
  353. tempL = (uint8_t)(tempHex & 0x00FF);
  354. cmd.bvalue[0] = tempH;
  355. cmd.bvalue[1] = tempL;
  356. cmd.bvalue[2] = led->color.r;
  357. cmd.bvalue[3] = led->color.g;
  358. cmd.bvalue[4] = led->color.b;
  359. }
  360. cmd.bvalue[0] &= led->state;
  361. cmd.bvalue[1] &= led->state;
  362. return diamondback_chroma_send_command(m, &cmd);
  363. }
  364. static int diamondback_chroma_send_set_led_mode_command(struct razer_mouse *m,
  365. struct diamondback_chroma_led *led)
  366. {
  367. struct diamondback_chroma_command cmd;
  368. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  369. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_LED_MODE;
  370. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_SET_LED_MODE);
  371. if (led->mode == DIAMONDBACK_CHROMA_LED_MODE_STATIC) {
  372. cmd.bvalue[0] = led->mode;
  373. cmd.bvalue[1] = led->color.r;
  374. cmd.bvalue[2] = led->color.g;
  375. cmd.bvalue[3] = led->color.b;
  376. } else {
  377. uint16_t tempHex;
  378. uint8_t tempH, tempL;
  379. tempHex = led->mode;
  380. tempH = (uint8_t)((tempHex & 0xFF00) >> 8);
  381. tempL = (uint8_t)(tempHex & 0x00FF);
  382. cmd.bvalue[0] = tempH;
  383. cmd.bvalue[1] = tempL;
  384. cmd.bvalue[2] = led->color.r;
  385. cmd.bvalue[3] = led->color.g;
  386. cmd.bvalue[4] = led->color.b;
  387. }
  388. cmd.bvalue[0] &= led->state;
  389. cmd.bvalue[1] &= led->state;
  390. return diamondback_chroma_send_command(m, &cmd);
  391. }
  392. static int diamondback_chroma_send_set_led_color_command(struct razer_mouse *m,
  393. struct diamondback_chroma_led *led)
  394. {
  395. struct diamondback_chroma_command cmd;
  396. cmd = DIAMONDBACK_CHROMA_COMMAND_INIT;
  397. cmd.size = DIAMONDBACK_CHROMA_REQUEST_SIZE_SET_LED_COLOR;
  398. cmd.request = cpu_to_be16(DIAMONDBACK_CHROMA_REQUEST_SET_LED_COLOR);
  399. if (led->mode == DIAMONDBACK_CHROMA_LED_MODE_STATIC) {
  400. cmd.bvalue[0] = led->mode;
  401. cmd.bvalue[1] = led->color.r;
  402. cmd.bvalue[2] = led->color.g;
  403. cmd.bvalue[3] = led->color.b;
  404. } else {
  405. uint16_t tempHex;
  406. uint8_t tempH, tempL;
  407. tempHex = led->mode;
  408. tempH = (uint8_t)((tempHex & 0xFF00) >> 8);
  409. tempL = (uint8_t)(tempHex & 0x00FF);
  410. cmd.bvalue[0] = tempH;
  411. cmd.bvalue[1] = tempL;
  412. cmd.bvalue[2] = led->color.r;
  413. cmd.bvalue[3] = led->color.g;
  414. cmd.bvalue[4] = led->color.b;
  415. }
  416. cmd.bvalue[0] &= led->state;
  417. cmd.bvalue[1] &= led->state;
  418. return diamondback_chroma_send_command(m, &cmd);
  419. }
  420. static int diamondback_chroma_get_fw_version(struct razer_mouse *m)
  421. {
  422. struct diamondback_chroma_driver_data *drv_data;
  423. drv_data = m->drv_data;
  424. return drv_data->fw_version;
  425. }
  426. static struct razer_mouse_profile *diamondback_chroma_get_profiles(struct razer_mouse *m)
  427. {
  428. struct diamondback_chroma_driver_data *drv_data;
  429. drv_data = m->drv_data;
  430. return &drv_data->profile;
  431. }
  432. static int diamondback_chroma_supported_axes(struct razer_mouse *m,
  433. struct razer_axis **res_ptr)
  434. {
  435. struct diamondback_chroma_driver_data *drv_data;
  436. drv_data = m->drv_data;
  437. *res_ptr = drv_data->axes;
  438. return ARRAY_SIZE(drv_data->axes);
  439. }
  440. static int diamondback_chroma_supported_dpimappings(struct razer_mouse *m,
  441. struct razer_mouse_dpimapping **res_ptr)
  442. {
  443. struct diamondback_chroma_driver_data *drv_data;
  444. drv_data = m->drv_data;
  445. *res_ptr = drv_data->dpimappings;
  446. return ARRAY_SIZE(drv_data->dpimappings);
  447. }
  448. static int diamondback_chroma_supported_resolutions(struct razer_mouse *m,
  449. enum razer_mouse_res **res_ptr)
  450. {
  451. size_t i;
  452. size_t step_number;
  453. step_number = DIAMONDBACK_CHROMA_MAX_RESOLUTION / DIAMONDBACK_CHROMA_RESOLUTION_STEP;
  454. *res_ptr = calloc(step_number, sizeof(enum razer_mouse_res));
  455. if (!*res_ptr)
  456. return -ENOMEM;
  457. for (i = 0; i < step_number; i++)
  458. (*res_ptr)[i] = (i + 1) * DIAMONDBACK_CHROMA_RESOLUTION_STEP;
  459. return step_number;
  460. }
  461. static int diamondback_chroma_supported_freqs(struct razer_mouse *m,
  462. enum razer_mouse_freq **res_ptr)
  463. {
  464. *res_ptr = malloc(sizeof(diamondback_chroma_freqs_list));
  465. if (!*res_ptr)
  466. return -ENOMEM;
  467. memcpy(*res_ptr, diamondback_chroma_freqs_list, sizeof(diamondback_chroma_freqs_list));
  468. return DIAMONDBACK_CHROMA_SUPPORTED_FREQ_NUM;
  469. }
  470. static enum razer_mouse_freq diamondback_chroma_get_freq(struct razer_mouse_profile *p)
  471. {
  472. struct diamondback_chroma_driver_data *drv_data;
  473. drv_data = p->mouse->drv_data;
  474. return drv_data->current_freq;
  475. }
  476. static struct razer_mouse_dpimapping *diamondback_chroma_get_dpimapping(struct razer_mouse_profile *p,
  477. struct razer_axis *axis)
  478. {
  479. struct diamondback_chroma_driver_data *drv_data;
  480. drv_data = p->mouse->drv_data;
  481. return drv_data->current_dpimapping;
  482. }
  483. static int diamondback_chroma_change_dpimapping(struct razer_mouse_dpimapping *d,
  484. enum razer_dimension dim,
  485. enum razer_mouse_res res)
  486. {
  487. struct diamondback_chroma_driver_data *drv_data;
  488. if (!(d->dimension_mask & (1 << dim)))
  489. return -EINVAL;
  490. if (res == RAZER_MOUSE_RES_UNKNOWN)
  491. res = RAZER_MOUSE_RES_1800DPI;
  492. if (res < RAZER_MOUSE_RES_100DPI || res > RAZER_MOUSE_RES_16000DPI)
  493. return -EINVAL;
  494. d->res[dim] = res;
  495. drv_data = d->mouse->drv_data;
  496. if (d == drv_data->current_dpimapping)
  497. return diamondback_chroma_send_set_resolution_command(d->mouse);
  498. return 0;
  499. }
  500. static int diamondback_chroma_led_toggle_state(struct razer_led *led,
  501. enum razer_led_state new_state)
  502. {
  503. struct diamondback_chroma_driver_data *drv_data;
  504. struct diamondback_chroma_led *priv_led;
  505. drv_data = led->u.mouse->drv_data;
  506. priv_led = diamondback_chroma_get_led(drv_data);
  507. if (!priv_led)
  508. return -EINVAL;
  509. switch (new_state) {
  510. case RAZER_LED_UNKNOWN:
  511. case RAZER_LED_ON:
  512. priv_led->state = DIAMONDBACK_CHROMA_LED_STATE_ON;
  513. break;
  514. case RAZER_LED_OFF:
  515. priv_led->state = DIAMONDBACK_CHROMA_LED_STATE_OFF;
  516. break;
  517. }
  518. return diamondback_chroma_send_set_led_state_command(led->u.mouse, priv_led);
  519. }
  520. static int diamondback_chroma_led_change_color(struct razer_led *led,
  521. const struct razer_rgb_color *new_color)
  522. {
  523. struct diamondback_chroma_driver_data *drv_data;
  524. struct diamondback_chroma_led *priv_led;
  525. drv_data = led->u.mouse->drv_data;
  526. priv_led = diamondback_chroma_get_led(drv_data);
  527. if (!priv_led)
  528. return -EINVAL;
  529. if (priv_led->mode == DIAMONDBACK_CHROMA_LED_MODE_SPECTRUM)
  530. return -EINVAL;
  531. priv_led->color = (struct diamondback_chroma_rgb_color){
  532. .r = new_color->r,
  533. .g = new_color->g,
  534. .b = new_color->b,
  535. };
  536. return diamondback_chroma_send_set_led_color_command(led->u.mouse, priv_led);
  537. }
  538. static int diamondback_chroma_set_freq(struct razer_mouse_profile *p,
  539. enum razer_mouse_freq freq)
  540. {
  541. struct diamondback_chroma_driver_data *drv_data;
  542. if (freq == RAZER_MOUSE_FREQ_UNKNOWN)
  543. freq = RAZER_MOUSE_FREQ_500HZ;
  544. if (freq != RAZER_MOUSE_FREQ_125HZ &&
  545. freq != RAZER_MOUSE_FREQ_500HZ &&
  546. freq != RAZER_MOUSE_FREQ_1000HZ)
  547. return -EINVAL;
  548. drv_data = p->mouse->drv_data;
  549. drv_data->current_freq = freq;
  550. return diamondback_chroma_send_set_frequency_command(p->mouse);
  551. }
  552. static int diamondback_chroma_set_dpimapping(struct razer_mouse_profile *p,
  553. struct razer_axis *axis,
  554. struct razer_mouse_dpimapping *d)
  555. {
  556. struct diamondback_chroma_driver_data *drv_data;
  557. if (axis && axis->id > 0)
  558. return -EINVAL;
  559. drv_data = p->mouse->drv_data;
  560. drv_data->current_dpimapping = &drv_data->dpimappings[d->nr];
  561. return diamondback_chroma_send_set_resolution_command(p->mouse);
  562. }
  563. static int diamondback_chroma_translate_led_mode(enum diamondback_chroma_led_mode mode)
  564. {
  565. switch (mode) {
  566. case DIAMONDBACK_CHROMA_LED_MODE_STATIC:
  567. return RAZER_LED_MODE_STATIC;
  568. case DIAMONDBACK_CHROMA_LED_MODE_BREATHING:
  569. return RAZER_LED_MODE_BREATHING;
  570. case DIAMONDBACK_CHROMA_LED_MODE_SPECTRUM:
  571. return RAZER_LED_MODE_SPECTRUM;
  572. case DIAMONDBACK_CHROMA_LED_MODE_WAVE:
  573. return RAZER_LED_MODE_WAVE;
  574. case DIAMONDBACK_CHROMA_LED_MODE_REACTION:
  575. return RAZER_LED_MODE_REACTION;
  576. default:
  577. return -EINVAL;
  578. }
  579. }
  580. static int diamondback_chroma_translate_razer_led_mode(enum razer_led_mode mode)
  581. {
  582. switch (mode) {
  583. case RAZER_LED_MODE_STATIC:
  584. return DIAMONDBACK_CHROMA_LED_MODE_STATIC;
  585. case RAZER_LED_MODE_BREATHING:
  586. return DIAMONDBACK_CHROMA_LED_MODE_BREATHING;
  587. case RAZER_LED_MODE_SPECTRUM:
  588. return DIAMONDBACK_CHROMA_LED_MODE_SPECTRUM;
  589. case RAZER_LED_MODE_WAVE:
  590. return DIAMONDBACK_CHROMA_LED_MODE_WAVE;
  591. case RAZER_LED_MODE_REACTION:
  592. return DIAMONDBACK_CHROMA_LED_MODE_REACTION;
  593. default:
  594. return -EINVAL;
  595. }
  596. }
  597. static int diamondback_chroma_led_set_mode(struct razer_led *led,
  598. enum razer_led_mode new_mode)
  599. {
  600. int err;
  601. struct diamondback_chroma_driver_data *drv_data;
  602. struct diamondback_chroma_led *priv_led;
  603. drv_data = led->u.mouse->drv_data;
  604. priv_led = diamondback_chroma_get_led(drv_data);
  605. if (!priv_led)
  606. return -EINVAL;
  607. err = diamondback_chroma_translate_razer_led_mode(new_mode);
  608. if (err < 0)
  609. return err;
  610. priv_led->mode = err;
  611. return diamondback_chroma_send_set_led_mode_command(led->u.mouse, priv_led);
  612. }
  613. static int diamondback_chroma_get_leds(struct razer_mouse *m,
  614. struct razer_led **leds_list)
  615. {
  616. unsigned int supported_modes;
  617. enum razer_led_state led_state;
  618. struct diamondback_chroma_driver_data *drv_data;
  619. struct razer_led *led;
  620. drv_data = m->drv_data;
  621. led = zalloc(sizeof(struct razer_led));
  622. if (!led)
  623. return -ENOMEM;
  624. supported_modes = (1 << RAZER_LED_MODE_BREATHING) |
  625. (1 << RAZER_LED_MODE_SPECTRUM) |
  626. (1 << RAZER_LED_MODE_STATIC) |
  627. (1 << RAZER_LED_MODE_WAVE) |
  628. (1 << RAZER_LED_MODE_REACTION);
  629. led_state = drv_data->led.state == DIAMONDBACK_CHROMA_LED_STATE_OFF ?
  630. RAZER_LED_OFF : RAZER_LED_ON;
  631. *led = (struct razer_led){
  632. .name = DIAMONDBACK_CHROMA_LED_NAME,
  633. .state = led_state,
  634. .u.mouse = m,
  635. .toggle_state = diamondback_chroma_led_toggle_state,
  636. .change_color = diamondback_chroma_led_change_color,
  637. .set_mode = diamondback_chroma_led_set_mode,
  638. .color = {
  639. .r = drv_data->led.color.r,
  640. .g = drv_data->led.color.g,
  641. .b = drv_data->led.color.b,
  642. .valid = 1,
  643. },
  644. .supported_modes_mask = supported_modes,
  645. .mode = diamondback_chroma_translate_led_mode(drv_data->led.mode),
  646. };
  647. *leds_list = led;
  648. return DIAMONDBACK_CHROMA_LED_NUM;
  649. }
  650. int razer_diamondback_chroma_init(struct razer_mouse *m,
  651. struct libusb_device *usbdev)
  652. {
  653. int err;
  654. size_t i;
  655. struct diamondback_chroma_driver_data *drv_data;
  656. struct diamondback_chroma_led *led;
  657. BUILD_BUG_ON(sizeof(struct diamondback_chroma_command) != 90);
  658. drv_data = zalloc(sizeof(*drv_data));
  659. if (!drv_data)
  660. return -ENOMEM;
  661. razer_event_spacing_init(&drv_data->packet_spacing,
  662. DIAMONDBACK_CHROMA_PACKET_SPACING_MS);
  663. for (i = 0; i < DIAMONDBACK_CHROMA_DPIMAPPINGS_NUM; i++) {
  664. drv_data->dpimappings[i] = (struct razer_mouse_dpimapping){
  665. .nr = i,
  666. .change = diamondback_chroma_change_dpimapping,
  667. .dimension_mask = (1 << RAZER_DIM_X) |
  668. (1 << RAZER_DIM_Y),
  669. .mouse = m,
  670. };
  671. drv_data->dpimappings[i].res[RAZER_DIM_X] =
  672. diamondback_chroma_resolution_stages_list[i];
  673. drv_data->dpimappings[i].res[RAZER_DIM_Y] =
  674. diamondback_chroma_resolution_stages_list[i];
  675. }
  676. drv_data->current_dpimapping = &drv_data->dpimappings[1];
  677. drv_data->current_freq = RAZER_MOUSE_FREQ_500HZ;
  678. drv_data->led = (struct diamondback_chroma_led){
  679. .mode = DIAMONDBACK_CHROMA_LED_MODE_STATIC,
  680. .state = DIAMONDBACK_CHROMA_LED_STATE_ON,
  681. .color = {0x00, 0xFF, 0x00},
  682. };
  683. razer_init_axes(drv_data->axes, "X/Y",
  684. RAZER_AXIS_INDEPENDENT_DPIMAPPING,
  685. "Scroll", 0, NULL, 0);
  686. m->drv_data = drv_data;
  687. if ((err = razer_usb_add_used_interface(m->usb_ctx, 0, 0)) ||
  688. (err = m->claim(m))) {
  689. free(drv_data);
  690. return err;
  691. }
  692. led = &drv_data->led;
  693. if ((err = diamondback_chroma_send_init_command (m)) ||
  694. (err = diamondback_chroma_send_set_resolution_command (m)) ||
  695. (err = diamondback_chroma_send_get_firmware_command (m)) ||
  696. (err = diamondback_chroma_send_get_serial_no_command (m)) ||
  697. (err = diamondback_chroma_send_set_frequency_command (m)) ||
  698. (err = diamondback_chroma_send_set_led_mode_command (m, led)) ||
  699. (err = diamondback_chroma_send_set_led_color_command (m, led))) {
  700. m->release(m);
  701. free(drv_data);
  702. return err;
  703. }
  704. m->release(m);
  705. drv_data->profile = (struct razer_mouse_profile){
  706. .mouse = m,
  707. .get_freq = diamondback_chroma_get_freq,
  708. .set_freq = diamondback_chroma_set_freq,
  709. .get_dpimapping = diamondback_chroma_get_dpimapping,
  710. .set_dpimapping = diamondback_chroma_set_dpimapping,
  711. };
  712. razer_generic_usb_gen_idstr(usbdev, m->usb_ctx->h,
  713. DIAMONDBACK_CHROMA_DEVICE_NAME, false,
  714. drv_data->serial, m->idstr);
  715. m->type = RAZER_MOUSETYPE_DIAMONDBACK_CHROMA;
  716. m->get_fw_version = diamondback_chroma_get_fw_version;
  717. m->global_get_leds = diamondback_chroma_get_leds;
  718. m->get_profiles = diamondback_chroma_get_profiles;
  719. m->supported_axes = diamondback_chroma_supported_axes;
  720. m->supported_resolutions = diamondback_chroma_supported_resolutions;
  721. m->supported_freqs = diamondback_chroma_supported_freqs;
  722. m->supported_dpimappings = diamondback_chroma_supported_dpimappings;
  723. return 0;
  724. }
  725. void razer_diamondback_chroma_release(struct razer_mouse *m)
  726. {
  727. struct diamondback_chroma_driver_data *drv_data;
  728. drv_data = m->drv_data;
  729. free(drv_data);
  730. m->drv_data = NULL;
  731. }