hw_naga.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /*
  2. * Lowlevel hardware access for the
  3. * Razer Naga mouse
  4. *
  5. * Important notice:
  6. * This hardware driver is based on reverse engineering, only.
  7. *
  8. * Copyright (C) 2007-2010 Michael Buesch <m@bues.ch>
  9. * Copyright (C) 2010 Bernd Michael Helm <naga@rw23.de>
  10. *
  11. * Naga-2012 fixes by Tibor Peluch <messani@gmail.com>
  12. *
  13. * This program is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU General Public License
  15. * as published by the Free Software Foundation; either version 2
  16. * of the License, or (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. */
  23. #include "hw_naga.h"
  24. #include "razer_private.h"
  25. #include <errno.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <stdint.h>
  29. #include <string.h>
  30. enum {
  31. NAGA_LED_SCROLL = 0,
  32. NAGA_LED_LOGO,
  33. NAGA_LED_THUMB_GRID,
  34. NAGA_NR_LEDS,
  35. };
  36. enum { /* Misc constants */
  37. /* Naga Classic/Epic/2012/Hex: from 100 to 5600 DPI. */
  38. NAGA_5600_NR_DPIMAPPINGS = 56,
  39. /* Naga 2014: from 100 to 8200 DPI. */
  40. NAGA_8200_NR_DPIMAPPINGS = 82,
  41. NAGA_NR_DPIMAPPINGS = NAGA_8200_NR_DPIMAPPINGS,
  42. NAGA_NR_AXES = 3,
  43. };
  44. struct naga_command {
  45. uint8_t status;
  46. uint8_t padding0[3];
  47. be16_t command;
  48. be16_t request;
  49. uint8_t values[5];
  50. uint8_t padding1[75];
  51. uint8_t checksum;
  52. uint8_t padding2;
  53. } _packed;
  54. struct naga_private {
  55. struct razer_mouse *m;
  56. /* Firmware version number. */
  57. uint16_t fw_version;
  58. /* The currently set LED states.
  59. * Note: unsupported LEDs for a particular Naga model
  60. * will be set to RAZER_LED_UNKNOWN */
  61. enum razer_led_state led_states[NAGA_NR_LEDS];
  62. /* The currently set frequency. */
  63. enum razer_mouse_freq frequency;
  64. /* The currently set resolution. */
  65. struct razer_mouse_dpimapping *cur_dpimapping_X;
  66. struct razer_mouse_dpimapping *cur_dpimapping_Y;
  67. struct razer_mouse_profile profile;
  68. struct razer_mouse_dpimapping dpimapping[NAGA_NR_DPIMAPPINGS];
  69. /* Number of mappings actually supported by this Naga model. */
  70. int nb_dpimappings;
  71. /* Model dependent method to initialize a resolution command. */
  72. void (*command_init_resolution)(struct naga_command *, struct naga_private *);
  73. struct razer_axis axes[NAGA_NR_AXES];
  74. bool commit_pending;
  75. struct razer_event_spacing packet_spacing;
  76. };
  77. #define NAGA_FW_MAJOR(ver) (((ver) >> 8) & 0xFF)
  78. #define NAGA_FW_MINOR(ver) ((ver) & 0xFF)
  79. #define NAGA_FW(major, minor) (((major) << 8) | (minor))
  80. static const struct
  81. {
  82. /* LED name. */
  83. const char *name;
  84. /* LED id when sending config command request. */
  85. uint8_t values[2];
  86. } naga_leds[NAGA_NR_LEDS] = {
  87. { "Scrollwheel", {0x01, 0x01} },
  88. { "GlowingLogo", {0x01, 0x04} },
  89. { "ThumbGrid", {0x01, 0x05} },
  90. };
  91. static void naga_command_init(struct naga_command *cmd)
  92. {
  93. memset(cmd, 0, sizeof(*cmd));
  94. }
  95. static void naga_command_init_resolution_5600(struct naga_command *cmd,
  96. struct naga_private *priv)
  97. {
  98. unsigned int xres, yres;
  99. naga_command_init(cmd);
  100. cmd->command = cpu_to_be16(0x0003);
  101. cmd->request = cpu_to_be16(0x0401);
  102. xres = (((unsigned int)priv->cur_dpimapping_X->res[RAZER_DIM_0] / 100) - 1) * 4;
  103. yres = (((unsigned int)priv->cur_dpimapping_Y->res[RAZER_DIM_0] / 100) - 1) * 4;
  104. cmd->values[0] = xres;
  105. cmd->values[1] = yres;
  106. }
  107. static void naga_command_init_resolution_8200(struct naga_command *cmd,
  108. struct naga_private *priv)
  109. {
  110. be16_t xres, yres;
  111. naga_command_init(cmd);
  112. cmd->command = cpu_to_be16(0x0007);
  113. cmd->request = cpu_to_be16(0x0405);
  114. xres = cpu_to_be16(priv->cur_dpimapping_X->res[RAZER_DIM_0]);
  115. yres = cpu_to_be16(priv->cur_dpimapping_Y->res[RAZER_DIM_0]);
  116. memcpy(cmd->values + 1, &xres, 2);
  117. memcpy(cmd->values + 3, &yres, 2);
  118. }
  119. static int naga_usb_write(struct naga_private *priv,
  120. int request, int command,
  121. void *buf, size_t size)
  122. {
  123. int err;
  124. razer_event_spacing_enter(&priv->packet_spacing);
  125. err = libusb_control_transfer(
  126. priv->m->usb_ctx->h,
  127. LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS |
  128. LIBUSB_RECIPIENT_INTERFACE,
  129. request, command, 0,
  130. (unsigned char *)buf, size,
  131. RAZER_USB_TIMEOUT);
  132. razer_event_spacing_leave(&priv->packet_spacing);
  133. if (err < 0 || (size_t)err != size) {
  134. razer_error("razer-naga: "
  135. "USB write 0x%02X 0x%02X failed: %d\n",
  136. request, command, err);
  137. return err;
  138. }
  139. return 0;
  140. }
  141. static int naga_usb_read(struct naga_private *priv,
  142. int request, int command,
  143. void *buf, size_t size)
  144. {
  145. int err, try;
  146. for (try = 0; try < 3; try++) {
  147. razer_event_spacing_enter(&priv->packet_spacing);
  148. err = libusb_control_transfer(
  149. priv->m->usb_ctx->h,
  150. LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS |
  151. LIBUSB_RECIPIENT_INTERFACE,
  152. request, command, 0,
  153. buf, size,
  154. RAZER_USB_TIMEOUT);
  155. razer_event_spacing_leave(&priv->packet_spacing);
  156. if (err >= 0 && (size_t)err == size)
  157. break;
  158. }
  159. if (err < 0 || (size_t)err != size) {
  160. razer_error("razer-naga: "
  161. "USB read 0x%02X 0x%02X failed: %d\n",
  162. request, command, err);
  163. return err;
  164. }
  165. return 0;
  166. }
  167. static int naga_send_command(struct naga_private *priv,
  168. struct naga_command *cmd)
  169. {
  170. int err;
  171. cmd->checksum = razer_xor8_checksum((uint8_t *)cmd + 2, sizeof(*cmd) - 4);
  172. err = naga_usb_write(priv, LIBUSB_REQUEST_SET_CONFIGURATION, 0x300,
  173. cmd, sizeof(*cmd));
  174. if (err)
  175. return err;
  176. err = naga_usb_read(priv, LIBUSB_REQUEST_CLEAR_FEATURE, 0x300,
  177. cmd, sizeof(*cmd));
  178. if (err)
  179. return err;
  180. if (cmd->status != 2 &&
  181. cmd->status != 1 &&
  182. cmd->status != 0) {
  183. razer_error("razer-naga: Command %04X/%04X failed with %02X\n",
  184. be16_to_cpu(cmd->command),
  185. be16_to_cpu(cmd->request),
  186. cmd->status);
  187. }
  188. return 0;
  189. }
  190. static int naga_read_fw_ver(struct naga_private *priv)
  191. {
  192. struct naga_command cmd;
  193. be16_t be16;
  194. uint16_t ver;
  195. int err;
  196. unsigned int i;
  197. /* Poke the device several times until it responds with a
  198. * valid version number */
  199. for (i = 0; i < 5; i++) {
  200. naga_command_init(&cmd);
  201. cmd.command = cpu_to_be16(0x0002);
  202. cmd.request = cpu_to_be16(0x0081);
  203. err = naga_send_command(priv, &cmd);
  204. memcpy(&be16, &cmd.values, 2);
  205. ver = be16_to_cpu(be16);
  206. if (!err && (ver & 0xFF00) != 0)
  207. return ver;
  208. razer_msleep(250);
  209. }
  210. razer_error("razer-naga: Failed to read firmware version\n");
  211. return -ENODEV;
  212. }
  213. static int naga_do_commit(struct naga_private *priv)
  214. {
  215. struct naga_command cmd;
  216. uint8_t freq;
  217. int led_id;
  218. int err;
  219. /* Set the resolution. */
  220. priv->command_init_resolution(&cmd, priv);
  221. err = naga_send_command(priv, &cmd);
  222. if (err)
  223. return err;
  224. /* Set the LEDs. */
  225. for (led_id = 0; led_id < NAGA_NR_LEDS; ++led_id) {
  226. if (RAZER_LED_UNKNOWN == priv->led_states[led_id]) {
  227. /* Not a supported LED on this model. */
  228. continue;
  229. }
  230. naga_command_init(&cmd);
  231. cmd.command = cpu_to_be16(0x0003);
  232. cmd.request = cpu_to_be16(0x0300);
  233. memcpy(cmd.values, naga_leds[led_id].values, 2);
  234. if (priv->led_states[led_id])
  235. cmd.values[2] = 1;
  236. err = naga_send_command(priv, &cmd);
  237. if (err)
  238. return err;
  239. }
  240. /* Set scan frequency. */
  241. switch (priv->frequency) {
  242. case RAZER_MOUSE_FREQ_125HZ:
  243. freq = 8;
  244. break;
  245. case RAZER_MOUSE_FREQ_500HZ:
  246. freq = 2;
  247. break;
  248. case RAZER_MOUSE_FREQ_1000HZ:
  249. case RAZER_MOUSE_FREQ_UNKNOWN:
  250. freq = 1;
  251. break;
  252. default:
  253. return -EINVAL;
  254. }
  255. naga_command_init(&cmd);
  256. cmd.command = cpu_to_be16(0x0001);
  257. cmd.request = cpu_to_be16(0x0005);
  258. cmd.values[0] = freq;
  259. err = naga_send_command(priv, &cmd);
  260. if (err)
  261. return err;
  262. return 0;
  263. }
  264. static int naga_get_fw_version(struct razer_mouse *m)
  265. {
  266. struct naga_private *priv = m->drv_data;
  267. return priv->fw_version;
  268. }
  269. static int naga_commit(struct razer_mouse *m, int force)
  270. {
  271. struct naga_private *priv = m->drv_data;
  272. int err = 0;
  273. if (!m->claim_count)
  274. return -EBUSY;
  275. if (priv->commit_pending || force) {
  276. err = naga_do_commit(priv);
  277. if (!err)
  278. priv->commit_pending = 0;
  279. }
  280. return err;
  281. }
  282. static int naga_led_toggle(struct razer_led *led,
  283. enum razer_led_state new_state)
  284. {
  285. struct razer_mouse *m = led->u.mouse;
  286. struct naga_private *priv = m->drv_data;
  287. if (led->id >= NAGA_NR_LEDS)
  288. return -EINVAL;
  289. if ((new_state != RAZER_LED_OFF) &&
  290. (new_state != RAZER_LED_ON))
  291. return -EINVAL;
  292. if (priv->led_states[led->id] == RAZER_LED_UNKNOWN) {
  293. /* Not a supported LED on this model. */
  294. return -EINVAL;
  295. }
  296. if (!priv->m->claim_count)
  297. return -EBUSY;
  298. priv->led_states[led->id] = new_state;
  299. priv->commit_pending = 1;
  300. return 0;
  301. }
  302. static int naga_get_leds(struct razer_mouse *m,
  303. struct razer_led **leds_list)
  304. {
  305. struct naga_private *priv = m->drv_data;
  306. struct razer_led *led;
  307. int nb_leds;
  308. int led_id;
  309. nb_leds = 0;
  310. *leds_list = NULL;
  311. for (led_id = 0; led_id < NAGA_NR_LEDS; ++led_id) {
  312. if (RAZER_LED_UNKNOWN == priv->led_states[led_id]) {
  313. /* Not a supported LED on this model. */
  314. continue;
  315. }
  316. led = zalloc(sizeof(struct razer_led));
  317. if (!led)
  318. return -ENOMEM;
  319. led->name = naga_leds[led_id].name;
  320. led->id = led_id;
  321. led->state = priv->led_states[led_id];
  322. led->toggle_state = naga_led_toggle;
  323. led->u.mouse = m;
  324. led->next = *leds_list;
  325. *leds_list = led;
  326. ++nb_leds;
  327. }
  328. return nb_leds;
  329. }
  330. static int naga_supported_freqs(struct razer_mouse *m,
  331. enum razer_mouse_freq **freq_list)
  332. {
  333. enum razer_mouse_freq *list;
  334. const int count = 3;
  335. list = zalloc(sizeof(*list) * count);
  336. if (!list)
  337. return -ENOMEM;
  338. list[0] = RAZER_MOUSE_FREQ_125HZ;
  339. list[1] = RAZER_MOUSE_FREQ_500HZ;
  340. list[2] = RAZER_MOUSE_FREQ_1000HZ;
  341. *freq_list = list;
  342. return count;
  343. }
  344. static enum razer_mouse_freq naga_get_freq(struct razer_mouse_profile *p)
  345. {
  346. struct naga_private *priv = p->mouse->drv_data;
  347. return priv->frequency;
  348. }
  349. static int naga_set_freq(struct razer_mouse_profile *p,
  350. enum razer_mouse_freq freq)
  351. {
  352. struct naga_private *priv = p->mouse->drv_data;
  353. if (!priv->m->claim_count)
  354. return -EBUSY;
  355. priv->frequency = freq;
  356. priv->commit_pending = 1;
  357. return 0;
  358. }
  359. static int naga_supported_axes(struct razer_mouse *m,
  360. struct razer_axis **axes_list)
  361. {
  362. struct naga_private *priv = m->drv_data;
  363. *axes_list = priv->axes;
  364. return ARRAY_SIZE(priv->axes);
  365. }
  366. static int naga_supported_resolutions(struct razer_mouse *m,
  367. enum razer_mouse_res **res_list)
  368. {
  369. struct naga_private *priv = m->drv_data;
  370. enum razer_mouse_res *list;
  371. int i;
  372. list = zalloc(sizeof(*list) * priv->nb_dpimappings);
  373. if (!list)
  374. return -ENOMEM;
  375. for (i = 0; i < priv->nb_dpimappings; i++)
  376. list[i] = (enum razer_mouse_res)((i + 1) * 100);
  377. *res_list = list;
  378. return priv->nb_dpimappings;
  379. }
  380. static struct razer_mouse_profile * naga_get_profiles(struct razer_mouse *m)
  381. {
  382. struct naga_private *priv = m->drv_data;
  383. return &priv->profile;
  384. }
  385. static int naga_supported_dpimappings(struct razer_mouse *m,
  386. struct razer_mouse_dpimapping **res_ptr)
  387. {
  388. struct naga_private *priv = m->drv_data;
  389. *res_ptr = &priv->dpimapping[0];
  390. return priv->nb_dpimappings;
  391. }
  392. static struct razer_mouse_dpimapping * naga_get_dpimapping(struct razer_mouse_profile *p,
  393. struct razer_axis *axis)
  394. {
  395. struct naga_private *priv = p->mouse->drv_data;
  396. if (!axis)
  397. axis = &priv->axes[0];
  398. if (axis->id == 0)
  399. return priv->cur_dpimapping_X;
  400. if (axis->id == 1)
  401. return priv->cur_dpimapping_Y;
  402. return NULL;
  403. }
  404. static int naga_set_dpimapping(struct razer_mouse_profile *p,
  405. struct razer_axis *axis,
  406. struct razer_mouse_dpimapping *d)
  407. {
  408. struct naga_private *priv = p->mouse->drv_data;
  409. if (!priv->m->claim_count)
  410. return -EBUSY;
  411. if (axis && axis->id >= ARRAY_SIZE(priv->axes))
  412. return -EINVAL;
  413. if (axis) {
  414. if (axis->id == 0)
  415. priv->cur_dpimapping_X = d;
  416. else if (axis->id == 1)
  417. priv->cur_dpimapping_Y = d;
  418. else
  419. return -EINVAL;
  420. } else {
  421. priv->cur_dpimapping_X = d;
  422. priv->cur_dpimapping_Y = d;
  423. }
  424. priv->commit_pending = 1;
  425. return 0;
  426. }
  427. int razer_naga_init(struct razer_mouse *m,
  428. struct libusb_device *usbdev)
  429. {
  430. struct naga_private *priv;
  431. struct libusb_device_descriptor desc;
  432. int i, fwver, err;
  433. const char *model;
  434. BUILD_BUG_ON(sizeof(struct naga_command) != 90);
  435. err = libusb_get_device_descriptor(usbdev, &desc);
  436. if (err) {
  437. razer_error("hw_naga: Failed to get device descriptor\n");
  438. return -EIO;
  439. }
  440. priv = zalloc(sizeof(struct naga_private));
  441. if (!priv)
  442. return -ENOMEM;
  443. priv->m = m;
  444. m->drv_data = priv;
  445. /* Need to wait some time between USB packets to
  446. * not confuse the firmware of some devices. */
  447. razer_event_spacing_init(&priv->packet_spacing, 25);
  448. err = razer_usb_add_used_interface(m->usb_ctx, 0, 0);
  449. if (err)
  450. goto err_free;
  451. err = m->claim(m);
  452. if (err) {
  453. razer_error("hw_naga: Failed to claim device\n");
  454. goto err_free;
  455. }
  456. /* Fetch firmware version */
  457. fwver = naga_read_fw_ver(priv);
  458. if (fwver < 0) {
  459. err = fwver;
  460. goto err_release;
  461. }
  462. priv->fw_version = fwver;
  463. if (desc.idProduct == RAZER_NAGA_PID_EPIC) {
  464. if (priv->fw_version < NAGA_FW(0x01, 0x04)) {
  465. razer_error("hw_naga: The firmware version %d.%d of this Naga "
  466. "has known bugs. Please upgrade to version 1.04 or later.",
  467. NAGA_FW_MAJOR(priv->fw_version),
  468. NAGA_FW_MINOR(priv->fw_version));
  469. m->flags |= RAZER_MOUSEFLG_SUGGESTFWUP;
  470. }
  471. }
  472. priv->frequency = RAZER_MOUSE_FREQ_1000HZ;
  473. priv->led_states[NAGA_LED_SCROLL] = RAZER_LED_ON;
  474. /* FIXME: not supported for Epic? */
  475. priv->led_states[NAGA_LED_LOGO] = RAZER_LED_ON;
  476. if (desc.idProduct == RAZER_NAGA_PID_2014)
  477. priv->led_states[NAGA_LED_THUMB_GRID] = RAZER_LED_ON;
  478. else
  479. priv->led_states[NAGA_LED_THUMB_GRID] = RAZER_LED_UNKNOWN;
  480. priv->profile.nr = 0;
  481. priv->profile.get_freq = naga_get_freq;
  482. priv->profile.set_freq = naga_set_freq;
  483. priv->profile.get_dpimapping = naga_get_dpimapping;
  484. priv->profile.set_dpimapping = naga_set_dpimapping;
  485. priv->profile.mouse = m;
  486. if (desc.idProduct == RAZER_NAGA_PID_2014) {
  487. priv->nb_dpimappings = NAGA_8200_NR_DPIMAPPINGS;
  488. priv->command_init_resolution = naga_command_init_resolution_8200;
  489. } else {
  490. priv->nb_dpimappings = NAGA_5600_NR_DPIMAPPINGS;
  491. priv->command_init_resolution = naga_command_init_resolution_5600;
  492. }
  493. for (i = 0; i < priv->nb_dpimappings; i++) {
  494. priv->dpimapping[i].nr = (unsigned int)i;
  495. priv->dpimapping[i].res[RAZER_DIM_0] = (enum razer_mouse_res)((i + 1) * 100);
  496. if (priv->dpimapping[i].res[RAZER_DIM_0] == 1000) {
  497. priv->cur_dpimapping_X = &priv->dpimapping[i];
  498. priv->cur_dpimapping_Y = &priv->dpimapping[i];
  499. }
  500. priv->dpimapping[i].dimension_mask = (1 << RAZER_DIM_0);
  501. priv->dpimapping[i].change = NULL;
  502. priv->dpimapping[i].mouse = m;
  503. }
  504. razer_init_axes(&priv->axes[0],
  505. "X", RAZER_AXIS_INDEPENDENT_DPIMAPPING,
  506. "Y", RAZER_AXIS_INDEPENDENT_DPIMAPPING,
  507. "Scroll", 0);
  508. m->type = RAZER_MOUSETYPE_NAGA;
  509. switch (desc.idProduct) {
  510. default:
  511. case RAZER_NAGA_PID_CLASSIC:
  512. model = "Naga";
  513. break;
  514. case RAZER_NAGA_PID_EPIC:
  515. model = "Naga Epic";
  516. break;
  517. case RAZER_NAGA_PID_2012:
  518. model = "Naga 2012";
  519. break;
  520. case RAZER_NAGA_PID_HEX:
  521. model = "Naga Hex";
  522. break;
  523. case RAZER_NAGA_PID_2014:
  524. model = "Naga 2014";
  525. break;
  526. }
  527. razer_generic_usb_gen_idstr(usbdev, m->usb_ctx->h, model, 1,
  528. NULL, m->idstr);
  529. m->get_fw_version = naga_get_fw_version;
  530. m->commit = naga_commit;
  531. m->global_get_leds = naga_get_leds;
  532. m->get_profiles = naga_get_profiles;
  533. m->supported_axes = naga_supported_axes;
  534. m->supported_resolutions = naga_supported_resolutions;
  535. m->supported_freqs = naga_supported_freqs;
  536. m->supported_dpimappings = naga_supported_dpimappings;
  537. err = naga_do_commit(priv);
  538. if (err) {
  539. razer_error("hw_naga: Failed to commit initial settings\n");
  540. goto err_release;
  541. }
  542. m->release(m);
  543. return 0;
  544. err_release:
  545. m->release(m);
  546. err_free:
  547. free(priv);
  548. return err;
  549. }
  550. void razer_naga_release(struct razer_mouse *m)
  551. {
  552. struct naga_private *priv = m->drv_data;
  553. free(priv);
  554. }