hw_boomslangce.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. /*
  2. * Lowlevel hardware access for the
  3. * Razer Boomslang Collector's Edition mouse
  4. *
  5. * Important notice:
  6. * This hardware driver is based on reverse engineering only.
  7. *
  8. * Copyright (C) 2010 Michael Buesch <m@bues.ch>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. */
  20. #include "hw_boomslangce.h"
  21. #include "razer_private.h"
  22. #include "buttonmapping.h"
  23. #include <errno.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <stdint.h>
  27. #include <string.h>
  28. enum {
  29. BOOMSLANGCE_LED_SCROLL = 0,
  30. BOOMSLANGCE_LED_GLOWPIPE,
  31. BOOMSLANGCE_NR_LEDS,
  32. };
  33. enum { /* Misc constants */
  34. BOOMSLANGCE_NR_PROFILES = 5,
  35. BOOMSLANGCE_NR_DPIMAPPINGS = 3,
  36. };
  37. /* The wire protocol data structures... */
  38. enum boomslangce_phys_button {
  39. /* Physical button IDs */
  40. BOOMSLANGCE_PHYSBUT_LEFT = 0x01, /* Left button */
  41. BOOMSLANGCE_PHYSBUT_RIGHT, /* Right button */
  42. BOOMSLANGCE_PHYSBUT_MIDDLE, /* Middle button */
  43. BOOMSLANGCE_PHYSBUT_LSIDE, /* Left side */
  44. BOOMSLANGCE_PHYSBUT_RSIDE, /* Right side */
  45. BOOMSLANGCE_PHYSBUT_SCROLLUP, /* Scroll up */
  46. BOOMSLANGCE_PHYSBUT_SCROLLDOWN, /* Scroll down */
  47. NR_BOOMSLANGCE_PHYSBUT = 7, /* Number of physical buttons */
  48. };
  49. enum boomslangce_button_function {
  50. /* Logical button function IDs */
  51. BOOMSLANGCE_BUTFUNC_LEFT = 0x01, /* Left button */
  52. BOOMSLANGCE_BUTFUNC_RIGHT = 0x02, /* Right button */
  53. BOOMSLANGCE_BUTFUNC_MIDDLE = 0x03, /* Middle button */
  54. BOOMSLANGCE_BUTFUNC_DPIUP = 0x0C, /* DPI down */
  55. BOOMSLANGCE_BUTFUNC_DPIDOWN = 0x0D, /* DPI down */
  56. BOOMSLANGCE_BUTFUNC_WIN5 = 0x0A, /* Windows button 5 */
  57. BOOMSLANGCE_BUTFUNC_WIN4 = 0x0B, /* Windows button 4 */
  58. BOOMSLANGCE_BUTFUNC_SCROLLUP = 0x30, /* Scroll wheel up */
  59. BOOMSLANGCE_BUTFUNC_SCROLLDOWN = 0x31, /* Scroll wheel down */
  60. };
  61. struct boomslangce_one_buttonmapping {
  62. uint8_t physical;
  63. uint8_t logical;
  64. } _packed;
  65. struct boomslangce_buttonmappings {
  66. struct boomslangce_one_buttonmapping left;
  67. uint8_t _padding0[46];
  68. struct boomslangce_one_buttonmapping right;
  69. uint8_t _padding1[46];
  70. struct boomslangce_one_buttonmapping middle;
  71. uint8_t _padding2[46];
  72. struct boomslangce_one_buttonmapping rside;
  73. uint8_t _padding3[46];
  74. struct boomslangce_one_buttonmapping lside;
  75. uint8_t _padding4[46];
  76. struct boomslangce_one_buttonmapping scrollup;
  77. uint8_t _padding5[46];
  78. struct boomslangce_one_buttonmapping scrolldown;
  79. uint8_t _padding6[42];
  80. } _packed;
  81. struct boomslangce_profcfg_cmd {
  82. le16_t packetlength;
  83. le16_t magic;
  84. le16_t profilenr;
  85. le16_t reply_packetlength; /* Only valid for read data */
  86. le16_t reply_magic; /* Only valid for read data */
  87. le16_t reply_profilenr;
  88. uint8_t dpisel;
  89. uint8_t freq;
  90. struct boomslangce_buttonmappings buttons;
  91. le16_t checksum;
  92. } _packed;
  93. #define BOOMSLANGCE_PROFCFG_MAGIC cpu_to_le16(0x0002)
  94. struct boomslangce_private {
  95. struct razer_mouse *m;
  96. uint16_t fw_version;
  97. /* The currently set LED states. */
  98. bool led_states[BOOMSLANGCE_NR_LEDS];
  99. /* The active profile. */
  100. struct razer_mouse_profile *cur_profile;
  101. /* Profile configuration (one per profile). */
  102. struct razer_mouse_profile profiles[BOOMSLANGCE_NR_PROFILES];
  103. /* The active DPI mapping; per profile. */
  104. struct razer_mouse_dpimapping *cur_dpimapping[BOOMSLANGCE_NR_PROFILES];
  105. /* The possible DPI mappings. */
  106. struct razer_mouse_dpimapping dpimappings[BOOMSLANGCE_NR_DPIMAPPINGS];
  107. /* The active scan frequency; per profile. */
  108. enum razer_mouse_freq cur_freq[BOOMSLANGCE_NR_PROFILES];
  109. /* The active button mapping; per profile. */
  110. struct boomslangce_buttonmappings buttons[BOOMSLANGCE_NR_PROFILES];
  111. bool commit_pending;
  112. struct razer_event_spacing commit_spacing;
  113. };
  114. /* A list of physical buttons on the device. */
  115. static struct razer_button boomslangce_physical_buttons[] = {
  116. { .id = BOOMSLANGCE_PHYSBUT_LEFT, .name = "Leftclick", },
  117. { .id = BOOMSLANGCE_PHYSBUT_RIGHT, .name = "Rightclick", },
  118. { .id = BOOMSLANGCE_PHYSBUT_MIDDLE, .name = "Middleclick", },
  119. { .id = BOOMSLANGCE_PHYSBUT_LSIDE, .name = "Leftside button", },
  120. { .id = BOOMSLANGCE_PHYSBUT_RSIDE, .name = "Rightside button", },
  121. { .id = BOOMSLANGCE_PHYSBUT_SCROLLUP, .name = "Scroll up", },
  122. { .id = BOOMSLANGCE_PHYSBUT_SCROLLDOWN, .name = "Scroll down", },
  123. };
  124. /* A list of possible button functions. */
  125. static struct razer_button_function boomslangce_button_functions[] = {
  126. { .id = BOOMSLANGCE_BUTFUNC_LEFT, .name = "Leftclick", },
  127. { .id = BOOMSLANGCE_BUTFUNC_RIGHT, .name = "Rightclick", },
  128. { .id = BOOMSLANGCE_BUTFUNC_MIDDLE, .name = "Middleclick", },
  129. { .id = BOOMSLANGCE_BUTFUNC_DPIUP, .name = "DPI switch up", },
  130. { .id = BOOMSLANGCE_BUTFUNC_DPIDOWN, .name = "DPI switch down", },
  131. { .id = BOOMSLANGCE_BUTFUNC_WIN5, .name = "Windows Button 5", },
  132. { .id = BOOMSLANGCE_BUTFUNC_WIN4, .name = "Windows Button 4", },
  133. { .id = BOOMSLANGCE_BUTFUNC_SCROLLUP, .name = "Scroll up", },
  134. { .id = BOOMSLANGCE_BUTFUNC_SCROLLDOWN, .name = "Scroll down", },
  135. };
  136. /* TODO: There are more functions */
  137. #define DEFINE_DEF_BUTMAP(mappingptr, phys, func) \
  138. .mappingptr = { .physical = BOOMSLANGCE_PHYSBUT_##phys, \
  139. .logical = BOOMSLANGCE_BUTFUNC_##func, \
  140. }
  141. static const struct boomslangce_buttonmappings boomslangce_default_buttonmap = {
  142. DEFINE_DEF_BUTMAP(left, LEFT, LEFT),
  143. DEFINE_DEF_BUTMAP(right, RIGHT, RIGHT),
  144. DEFINE_DEF_BUTMAP(middle, MIDDLE, MIDDLE),
  145. DEFINE_DEF_BUTMAP(lside, LSIDE, WIN5),
  146. DEFINE_DEF_BUTMAP(rside, RSIDE, WIN4),
  147. DEFINE_DEF_BUTMAP(scrollup, SCROLLUP, SCROLLUP),
  148. DEFINE_DEF_BUTMAP(scrolldown, SCROLLDOWN, SCROLLDOWN),
  149. };
  150. static struct boomslangce_one_buttonmapping *
  151. boomslangce_buttonid_to_mapping(struct boomslangce_buttonmappings *mappings,
  152. enum boomslangce_phys_button id)
  153. {
  154. switch (id) {
  155. case BOOMSLANGCE_PHYSBUT_LEFT:
  156. return &mappings->left;
  157. case BOOMSLANGCE_PHYSBUT_RIGHT:
  158. return &mappings->right;
  159. case BOOMSLANGCE_PHYSBUT_MIDDLE:
  160. return &mappings->middle;
  161. case BOOMSLANGCE_PHYSBUT_LSIDE:
  162. return &mappings->lside;
  163. case BOOMSLANGCE_PHYSBUT_RSIDE:
  164. return &mappings->rside;
  165. case BOOMSLANGCE_PHYSBUT_SCROLLUP:
  166. return &mappings->scrollup;
  167. case BOOMSLANGCE_PHYSBUT_SCROLLDOWN:
  168. return &mappings->scrolldown;
  169. }
  170. return NULL;
  171. }
  172. static bool verify_buttons(const struct boomslangce_buttonmappings *map)
  173. {
  174. if (!razer_buffer_is_all_zero(map->_padding0, sizeof(map->_padding0)) ||
  175. !razer_buffer_is_all_zero(map->_padding1, sizeof(map->_padding1)) ||
  176. !razer_buffer_is_all_zero(map->_padding2, sizeof(map->_padding2)) ||
  177. !razer_buffer_is_all_zero(map->_padding3, sizeof(map->_padding3)) ||
  178. !razer_buffer_is_all_zero(map->_padding4, sizeof(map->_padding4)) ||
  179. !razer_buffer_is_all_zero(map->_padding5, sizeof(map->_padding5)) ||
  180. !razer_buffer_is_all_zero(map->_padding6, sizeof(map->_padding6)))
  181. return 0;
  182. /*
  183. if (map->left.physical != BOOMSLANGCE_PHYSBUT_LEFT ||
  184. map->right.physical != BOOMSLANGCE_PHYSBUT_RIGHT ||
  185. map->middle.physical != BOOMSLANGCE_PHYSBUT_MIDDLE ||
  186. map->lside.physical != BOOMSLANGCE_PHYSBUT_LSIDE ||
  187. map->rside.physical != BOOMSLANGCE_PHYSBUT_RSIDE ||
  188. map->scrollup.physical != BOOMSLANGCE_PHYSBUT_SCROLLUP ||
  189. map->scrolldown.physical != BOOMSLANGCE_PHYSBUT_SCROLLDOWN)
  190. return 0;*/
  191. return 1;
  192. }
  193. static int boomslangce_usb_write(struct boomslangce_private *priv,
  194. int request, int command, int index,
  195. void *buf, size_t size)
  196. {
  197. int err;
  198. err = libusb_control_transfer(
  199. priv->m->usb_ctx->h,
  200. LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS |
  201. LIBUSB_RECIPIENT_OTHER,
  202. request, command, index,
  203. (unsigned char *)buf, size, RAZER_USB_TIMEOUT);
  204. if (err < 0 || (size_t)err != size) {
  205. razer_error("razer-boomslangce: "
  206. "USB write 0x%02X 0x%02X 0x%02X failed: %d\n",
  207. request, command, index, err);
  208. return -EIO;
  209. }
  210. return 0;
  211. }
  212. static int boomslangce_usb_read(struct boomslangce_private *priv,
  213. int request, int command, int index,
  214. void *buf, size_t size)
  215. {
  216. int err;
  217. err = libusb_control_transfer(
  218. priv->m->usb_ctx->h,
  219. LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS |
  220. LIBUSB_RECIPIENT_OTHER,
  221. request, command, index,
  222. (unsigned char *)buf, size, RAZER_USB_TIMEOUT);
  223. if (err < 0 || (size_t)err != size) {
  224. razer_error("razer-boomslangce: "
  225. "USB read 0x%02X 0x%02X 0x%02X failed: %d\n",
  226. request, command, index, err);
  227. return -EIO;
  228. }
  229. return 0;
  230. }
  231. static int boomslangce_read_fw_ver(struct boomslangce_private *priv)
  232. {
  233. char buf[2];
  234. uint16_t ver;
  235. buf[0] = 0;//TODO
  236. buf[1] = 0;
  237. ver = buf[0];
  238. ver <<= 8;
  239. ver |= buf[1];
  240. return ver;
  241. }
  242. static int boomslangce_do_commit(struct boomslangce_private *priv)
  243. {
  244. union {
  245. struct boomslangce_profcfg_cmd profcfg;
  246. uint8_t chunks[64 * 6];
  247. } _packed u;
  248. uint8_t *chunk;
  249. unsigned int i, j;
  250. int err;
  251. unsigned char value;
  252. BUILD_BUG_ON(sizeof(u) != 0x180);
  253. razer_event_spacing_enter(&priv->commit_spacing);
  254. /* Upload the profile config */
  255. for (i = 0; i < BOOMSLANGCE_NR_PROFILES; i++) {
  256. memset(&u, 0, sizeof(u));
  257. u.profcfg.packetlength = cpu_to_le16(sizeof(u.profcfg));
  258. u.profcfg.magic = BOOMSLANGCE_PROFCFG_MAGIC;
  259. u.profcfg.profilenr = cpu_to_le16(i + 1);
  260. u.profcfg.reply_profilenr = u.profcfg.profilenr;
  261. switch (priv->cur_dpimapping[i]->res[RAZER_DIM_0]) {
  262. default:
  263. case RAZER_MOUSE_RES_400DPI:
  264. u.profcfg.dpisel = 4;
  265. break;
  266. case RAZER_MOUSE_RES_800DPI:
  267. u.profcfg.dpisel = 3;
  268. break;
  269. case RAZER_MOUSE_RES_1800DPI:
  270. u.profcfg.dpisel = 2;
  271. break;
  272. }
  273. switch (priv->cur_freq[i]) {
  274. default:
  275. case RAZER_MOUSE_FREQ_125HZ:
  276. u.profcfg.freq = 3;
  277. break;
  278. case RAZER_MOUSE_FREQ_500HZ:
  279. u.profcfg.freq = 2;
  280. break;
  281. case RAZER_MOUSE_FREQ_1000HZ:
  282. u.profcfg.freq = 1;
  283. break;
  284. }
  285. u.profcfg.buttons = priv->buttons[i];
  286. u.profcfg.checksum = razer_xor16_checksum(&u.profcfg,
  287. sizeof(u.profcfg) - 2);
  288. /* The profile config is committed in 64byte chunks */
  289. chunk = &u.chunks[0];
  290. for (j = 0; j < 6; j++, chunk += 64) {
  291. err = boomslangce_usb_write(priv, LIBUSB_REQUEST_SET_CONFIGURATION,
  292. j + 1, 0, chunk, 64);
  293. if (err)
  294. goto out;
  295. }
  296. /* Commit the profile */
  297. value = i + 1;
  298. boomslangce_usb_write(priv, LIBUSB_REQUEST_SET_CONFIGURATION,
  299. 0x02, 3, &value, sizeof(value));
  300. /* Read back the result */
  301. BUILD_BUG_ON(0x156 + 6 != sizeof(u.profcfg));
  302. memset(&u, 0, sizeof(u));
  303. err = boomslangce_usb_read(priv, LIBUSB_REQUEST_CLEAR_FEATURE,
  304. 0x01, 0, ((uint8_t *)&u.profcfg) + 6,
  305. sizeof(u.profcfg) - 6);
  306. if (err)
  307. goto out;
  308. if (razer_xor16_checksum(&u.profcfg, sizeof(u.profcfg))) {
  309. razer_error("hw_boomslangce: Profile commit checksum mismatch\n");
  310. err = -EIO;
  311. goto out;
  312. }
  313. }
  314. /* Select the profile */
  315. value = priv->cur_profile->nr + 1;
  316. err = boomslangce_usb_write(priv, LIBUSB_REQUEST_SET_CONFIGURATION,
  317. 0x02, 1, &value, sizeof(value));
  318. if (err)
  319. goto out;
  320. /* Switch LED states */
  321. value = 0;
  322. if (priv->led_states[BOOMSLANGCE_LED_SCROLL])
  323. value |= 0x01;
  324. if (priv->led_states[BOOMSLANGCE_LED_GLOWPIPE])
  325. value |= 0x02;
  326. err = boomslangce_usb_write(priv, LIBUSB_REQUEST_SET_CONFIGURATION,
  327. 0x02, 5, &value, sizeof(value));
  328. if (err)
  329. goto out;
  330. err = 0;
  331. out:
  332. razer_event_spacing_leave(&priv->commit_spacing);
  333. return err;
  334. }
  335. static int boomslangce_read_config_from_hw(struct boomslangce_private *priv)
  336. {
  337. struct boomslangce_profcfg_cmd profcfg;
  338. unsigned int i;
  339. unsigned char value;
  340. int err;
  341. /* Assign sane defaults. */
  342. for (i = 0; i < BOOMSLANGCE_NR_PROFILES; i++) {
  343. priv->buttons[i] = boomslangce_default_buttonmap;
  344. priv->cur_freq[i] = RAZER_MOUSE_FREQ_1000HZ;
  345. priv->cur_dpimapping[i] = &priv->dpimappings[0];
  346. }
  347. /* Read the current profile number. */
  348. err = boomslangce_usb_read(priv, LIBUSB_REQUEST_CLEAR_FEATURE,
  349. 0x01, 0, &value, sizeof(value));
  350. if (err)
  351. return err;
  352. if (value < 1 || value > BOOMSLANGCE_NR_PROFILES) {
  353. razer_error("hw_boomslangce: Got invalid profile number\n");
  354. return -EIO;
  355. }
  356. priv->cur_profile = &priv->profiles[value - 1];
  357. /* Read the profiles config */
  358. for (i = 0; i < BOOMSLANGCE_NR_PROFILES; i++) {
  359. BUILD_BUG_ON(0x156 + 6 != sizeof(profcfg));
  360. /* Request profile config */
  361. value = i + 1;
  362. err = boomslangce_usb_write(priv, LIBUSB_REQUEST_SET_CONFIGURATION,
  363. 0x02, 3, &value, sizeof(value));
  364. if (err)
  365. return err;
  366. /* Read profile config */
  367. memset(&profcfg, 0, sizeof(profcfg));
  368. err = boomslangce_usb_read(priv, LIBUSB_REQUEST_CLEAR_FEATURE,
  369. 0x01, 0, ((uint8_t *)&profcfg) + 6,
  370. sizeof(profcfg) - 6);
  371. if (err)
  372. return err;
  373. if (razer_xor16_checksum(&profcfg, sizeof(profcfg))) {
  374. razer_error("hw_boomslangce: Read profile data checksum mismatch\n");
  375. return -EIO;
  376. }
  377. if (le16_to_cpu(profcfg.reply_profilenr) != i + 1) {
  378. razer_error("hw_boomslangce: Got invalid profile nr in profile config\n");
  379. return -EIO;
  380. }
  381. switch (profcfg.dpisel) {
  382. case 4:
  383. priv->cur_dpimapping[i] = razer_mouse_get_dpimapping_by_res(
  384. priv->dpimappings, ARRAY_SIZE(priv->dpimappings),
  385. RAZER_DIM_0, RAZER_MOUSE_RES_400DPI);
  386. break;
  387. case 3:
  388. priv->cur_dpimapping[i] = razer_mouse_get_dpimapping_by_res(
  389. priv->dpimappings, ARRAY_SIZE(priv->dpimappings),
  390. RAZER_DIM_0, RAZER_MOUSE_RES_800DPI);
  391. break;
  392. case 2:
  393. priv->cur_dpimapping[i] = razer_mouse_get_dpimapping_by_res(
  394. priv->dpimappings, ARRAY_SIZE(priv->dpimappings),
  395. RAZER_DIM_0, RAZER_MOUSE_RES_1800DPI);
  396. break;
  397. default:
  398. razer_error("hw_boomslangce: Got invalid DPI mapping selection\n");
  399. return -EIO;
  400. }
  401. if (!priv->cur_dpimapping[i]) {
  402. razer_error("hw_boomslangce: Internal error: Did not find dpimapping\n");
  403. return -ENODEV;
  404. }
  405. switch (profcfg.freq) {
  406. case 3:
  407. priv->cur_freq[i] = RAZER_MOUSE_FREQ_125HZ;
  408. break;
  409. case 2:
  410. priv->cur_freq[i] = RAZER_MOUSE_FREQ_500HZ;
  411. break;
  412. case 1:
  413. priv->cur_freq[i] = RAZER_MOUSE_FREQ_1000HZ;
  414. break;
  415. default:
  416. razer_error("hw_boomslangce: Got invalid frequency selection\n");
  417. return -EIO;
  418. }
  419. if (!verify_buttons(&profcfg.buttons)) {
  420. razer_error("hw_boomslangce: Got invalid buttons map\n");
  421. return -EIO;
  422. }
  423. priv->buttons[i] = profcfg.buttons;
  424. }
  425. /* Read the LED states */
  426. // err = boomslang_usb_read(priv, LIBUSB_REQUEST_
  427. //TODO
  428. return 0;
  429. }
  430. static int boomslangce_get_fw_version(struct razer_mouse *m)
  431. {
  432. struct boomslangce_private *priv = m->drv_data;
  433. return priv->fw_version;
  434. }
  435. static int boomslangce_commit(struct razer_mouse *m, int force)
  436. {
  437. struct boomslangce_private *priv = m->drv_data;
  438. int err = 0;
  439. if (!m->claim_count)
  440. return -EBUSY;
  441. if (priv->commit_pending || force) {
  442. err = boomslangce_do_commit(priv);
  443. if (!err)
  444. priv->commit_pending = 0;
  445. }
  446. return err;
  447. }
  448. static struct razer_mouse_profile * boomslangce_get_profiles(struct razer_mouse *m)
  449. {
  450. struct boomslangce_private *priv = m->drv_data;
  451. return &priv->profiles[0];
  452. }
  453. static struct razer_mouse_profile * boomslangce_get_active_profile(struct razer_mouse *m)
  454. {
  455. struct boomslangce_private *priv = m->drv_data;
  456. return priv->cur_profile;
  457. }
  458. static int boomslangce_set_active_profile(struct razer_mouse *m,
  459. struct razer_mouse_profile *p)
  460. {
  461. struct boomslangce_private *priv = m->drv_data;
  462. if (!priv->m->claim_count)
  463. return -EBUSY;
  464. priv->cur_profile = p;
  465. priv->commit_pending = 1;
  466. return 0;
  467. }
  468. static int boomslangce_supported_resolutions(struct razer_mouse *m,
  469. enum razer_mouse_res **res_list)
  470. {
  471. enum razer_mouse_res *list;
  472. const int count = 3;
  473. list = zalloc(sizeof(*list) * count);
  474. if (!list)
  475. return -ENOMEM;
  476. list[0] = RAZER_MOUSE_RES_400DPI;
  477. list[1] = RAZER_MOUSE_RES_800DPI;
  478. list[2] = RAZER_MOUSE_RES_1800DPI;
  479. *res_list = list;
  480. return count;
  481. }
  482. static int boomslangce_supported_freqs(struct razer_mouse *m,
  483. enum razer_mouse_freq **freq_list)
  484. {
  485. enum razer_mouse_freq *list;
  486. const int count = 3;
  487. list = zalloc(sizeof(*list) * count);
  488. if (!list)
  489. return -ENOMEM;
  490. list[0] = RAZER_MOUSE_FREQ_125HZ;
  491. list[1] = RAZER_MOUSE_FREQ_500HZ;
  492. list[2] = RAZER_MOUSE_FREQ_1000HZ;
  493. *freq_list = list;
  494. return count;
  495. }
  496. static enum razer_mouse_freq boomslangce_get_freq(struct razer_mouse_profile *p)
  497. {
  498. struct boomslangce_private *priv = p->mouse->drv_data;
  499. if (p->nr >= ARRAY_SIZE(priv->cur_freq))
  500. return -EINVAL;
  501. return priv->cur_freq[p->nr];
  502. }
  503. static int boomslangce_set_freq(struct razer_mouse_profile *p,
  504. enum razer_mouse_freq freq)
  505. {
  506. struct boomslangce_private *priv = p->mouse->drv_data;
  507. if (!priv->m->claim_count)
  508. return -EBUSY;
  509. if (p->nr >= ARRAY_SIZE(priv->cur_freq))
  510. return -EINVAL;
  511. priv->cur_freq[p->nr] = freq;
  512. priv->commit_pending = 1;
  513. return 0;
  514. }
  515. static int boomslangce_supported_dpimappings(struct razer_mouse *m,
  516. struct razer_mouse_dpimapping **res_ptr)
  517. {
  518. struct boomslangce_private *priv = m->drv_data;
  519. *res_ptr = &priv->dpimappings[0];
  520. return ARRAY_SIZE(priv->dpimappings);
  521. }
  522. static struct razer_mouse_dpimapping * boomslangce_get_dpimapping(struct razer_mouse_profile *p,
  523. struct razer_axis *axis)
  524. {
  525. struct boomslangce_private *priv = p->mouse->drv_data;
  526. if (p->nr >= ARRAY_SIZE(priv->cur_dpimapping))
  527. return NULL;
  528. return priv->cur_dpimapping[p->nr];
  529. }
  530. static int boomslangce_set_dpimapping(struct razer_mouse_profile *p,
  531. struct razer_axis *axis,
  532. struct razer_mouse_dpimapping *d)
  533. {
  534. struct boomslangce_private *priv = p->mouse->drv_data;
  535. if (!priv->m->claim_count)
  536. return -EBUSY;
  537. if (p->nr >= ARRAY_SIZE(priv->cur_dpimapping))
  538. return -EINVAL;
  539. priv->cur_dpimapping[p->nr] = d;
  540. priv->commit_pending = 1;
  541. return 0;
  542. }
  543. static int boomslangce_led_toggle(struct razer_led *led,
  544. enum razer_led_state new_state)
  545. {
  546. struct razer_mouse *m = led->u.mouse;
  547. struct boomslangce_private *priv = m->drv_data;
  548. if (led->id >= BOOMSLANGCE_NR_LEDS)
  549. return -EINVAL;
  550. if ((new_state != RAZER_LED_OFF) &&
  551. (new_state != RAZER_LED_ON))
  552. return -EINVAL;
  553. if (!m->claim_count)
  554. return -EBUSY;
  555. priv->led_states[led->id] = new_state;
  556. priv->commit_pending = 1;
  557. return 0;
  558. }
  559. static int boomslangce_get_leds(struct razer_mouse *m,
  560. struct razer_led **leds_list)
  561. {
  562. struct boomslangce_private *priv = m->drv_data;
  563. struct razer_led *scroll, *logo;
  564. scroll = zalloc(sizeof(struct razer_led));
  565. if (!scroll)
  566. return -ENOMEM;
  567. logo = zalloc(sizeof(struct razer_led));
  568. if (!logo) {
  569. free(scroll);
  570. return -ENOMEM;
  571. }
  572. scroll->name = "Scrollwheel";
  573. scroll->id = BOOMSLANGCE_LED_SCROLL;
  574. scroll->state = priv->led_states[BOOMSLANGCE_LED_SCROLL];
  575. scroll->toggle_state = boomslangce_led_toggle;
  576. scroll->u.mouse = m;
  577. logo->name = "GlowPipe";
  578. logo->id = BOOMSLANGCE_LED_GLOWPIPE;
  579. logo->state = priv->led_states[BOOMSLANGCE_LED_GLOWPIPE];
  580. logo->toggle_state = boomslangce_led_toggle;
  581. logo->u.mouse = m;
  582. /* Link the list */
  583. *leds_list = scroll;
  584. scroll->next = logo;
  585. logo->next = NULL;
  586. return BOOMSLANGCE_NR_LEDS;
  587. }
  588. static int boomslangce_supported_buttons(struct razer_mouse *m,
  589. struct razer_button **res_ptr)
  590. {
  591. *res_ptr = boomslangce_physical_buttons;
  592. return ARRAY_SIZE(boomslangce_physical_buttons);
  593. }
  594. static int boomslangce_supported_button_functions(struct razer_mouse *m,
  595. struct razer_button_function **res_ptr)
  596. {
  597. *res_ptr = boomslangce_button_functions;
  598. return ARRAY_SIZE(boomslangce_button_functions);
  599. }
  600. static struct razer_button_function * boomslangce_get_button_function(struct razer_mouse_profile *p,
  601. struct razer_button *b)
  602. {
  603. struct boomslangce_private *priv = p->mouse->drv_data;
  604. struct boomslangce_buttonmappings *m;
  605. struct boomslangce_one_buttonmapping *one;
  606. unsigned int i;
  607. if (p->nr > ARRAY_SIZE(priv->buttons))
  608. return NULL;
  609. m = &priv->buttons[p->nr];
  610. one = boomslangce_buttonid_to_mapping(m, b->id);
  611. if (!one)
  612. return NULL;
  613. for (i = 0; i < ARRAY_SIZE(boomslangce_button_functions); i++) {
  614. if (boomslangce_button_functions[i].id == one->logical)
  615. return &boomslangce_button_functions[i];
  616. }
  617. return NULL;
  618. }
  619. static int boomslangce_set_button_function(struct razer_mouse_profile *p,
  620. struct razer_button *b,
  621. struct razer_button_function *f)
  622. {
  623. struct boomslangce_private *priv = p->mouse->drv_data;
  624. struct boomslangce_buttonmappings *m;
  625. struct boomslangce_one_buttonmapping *one;
  626. if (!priv->m->claim_count)
  627. return -EBUSY;
  628. if (p->nr > ARRAY_SIZE(priv->buttons))
  629. return -EINVAL;
  630. m = &priv->buttons[p->nr];
  631. one = boomslangce_buttonid_to_mapping(m, b->id);
  632. if (!one)
  633. return -ENODEV;
  634. one->logical = f->id;
  635. priv->commit_pending = 1;
  636. return 0;
  637. }
  638. int razer_boomslangce_init(struct razer_mouse *m,
  639. struct libusb_device *usbdev)
  640. {
  641. struct boomslangce_private *priv;
  642. unsigned int i;
  643. int err;
  644. BUILD_BUG_ON(sizeof(struct boomslangce_profcfg_cmd) != 0x15C);
  645. priv = zalloc(sizeof(struct boomslangce_private));
  646. if (!priv)
  647. return -ENOMEM;
  648. priv->m = m;
  649. m->drv_data = priv;
  650. /* We need to wait some time between commits */
  651. razer_event_spacing_init(&priv->commit_spacing, 250);
  652. err = razer_usb_add_used_interface(m->usb_ctx, 0, 0);
  653. err |= razer_usb_add_used_interface(m->usb_ctx, 1, 0);
  654. if (err) {
  655. err = -EIO;
  656. goto err_free;
  657. }
  658. priv->dpimappings[0].nr = 0;
  659. priv->dpimappings[0].res[RAZER_DIM_0] = RAZER_MOUSE_RES_400DPI;
  660. priv->dpimappings[0].dimension_mask = (1 << RAZER_DIM_0);
  661. priv->dpimappings[0].mouse = m;
  662. priv->dpimappings[1].nr = 1;
  663. priv->dpimappings[1].res[RAZER_DIM_0] = RAZER_MOUSE_RES_800DPI;
  664. priv->dpimappings[1].dimension_mask = (1 << RAZER_DIM_0);
  665. priv->dpimappings[1].mouse = m;
  666. priv->dpimappings[2].nr = 2;
  667. priv->dpimappings[2].res[RAZER_DIM_0] = RAZER_MOUSE_RES_1800DPI;
  668. priv->dpimappings[2].dimension_mask = (1 << RAZER_DIM_0);
  669. priv->dpimappings[2].mouse = m;
  670. for (i = 0; i < BOOMSLANGCE_NR_PROFILES; i++) {
  671. priv->profiles[i].nr = i;
  672. priv->profiles[i].get_freq = boomslangce_get_freq;
  673. priv->profiles[i].set_freq = boomslangce_set_freq;
  674. priv->profiles[i].get_dpimapping = boomslangce_get_dpimapping;
  675. priv->profiles[i].set_dpimapping = boomslangce_set_dpimapping;
  676. priv->profiles[i].get_button_function = boomslangce_get_button_function;
  677. priv->profiles[i].set_button_function = boomslangce_set_button_function;
  678. priv->profiles[i].mouse = m;
  679. }
  680. for (i = 0; i < BOOMSLANGCE_NR_LEDS; i++)
  681. priv->led_states[i] = RAZER_LED_ON;
  682. err = m->claim(m);
  683. if (err) {
  684. razer_error("hw_boomslangce: "
  685. "Failed to initially claim the device\n");
  686. goto err_free;
  687. }
  688. err = boomslangce_read_fw_ver(priv);
  689. if (err) {
  690. razer_error("hw_boomslangce: Failed to fetch firmware version number\n");
  691. goto err_release;
  692. }
  693. err = boomslangce_read_config_from_hw(priv);
  694. if (err) {
  695. razer_error("hw_boomslangce: Failed to read config from hardware\n");
  696. goto err_release;
  697. }
  698. m->type = RAZER_MOUSETYPE_BOOMSLANGCE;
  699. razer_generic_usb_gen_idstr(usbdev, NULL, "Boomslang-CE", 1,
  700. NULL, m->idstr);
  701. m->get_fw_version = boomslangce_get_fw_version;
  702. m->commit = boomslangce_commit;
  703. m->global_get_leds = boomslangce_get_leds;
  704. m->nr_profiles = BOOMSLANGCE_NR_PROFILES;
  705. m->get_profiles = boomslangce_get_profiles;
  706. m->get_active_profile = boomslangce_get_active_profile;
  707. m->set_active_profile = boomslangce_set_active_profile;
  708. m->supported_resolutions = boomslangce_supported_resolutions;
  709. m->supported_freqs = boomslangce_supported_freqs;
  710. m->supported_dpimappings = boomslangce_supported_dpimappings;
  711. m->supported_buttons = boomslangce_supported_buttons;
  712. m->supported_button_functions = boomslangce_supported_button_functions;
  713. err = boomslangce_do_commit(priv);
  714. if (err) {
  715. razer_error("hw_boomslangce: Failed to commit initial config\n");
  716. goto err_release;
  717. }
  718. m->release(m);
  719. return 0;
  720. err_release:
  721. m->release(m);
  722. err_free:
  723. free(priv);
  724. return err;
  725. }
  726. void razer_boomslangce_release(struct razer_mouse *m)
  727. {
  728. struct boomslangce_private *priv = m->drv_data;
  729. free(priv);
  730. }