logips2pp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /*
  2. * Logitech PS/2++ mouse driver
  3. *
  4. * Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
  5. * Copyright (c) 2003 Eric Wong <eric@yhbt.net>
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License version 2 as published by
  9. * the Free Software Foundation.
  10. */
  11. #include <linux/bitops.h>
  12. #include <linux/input.h>
  13. #include <linux/serio.h>
  14. #include <linux/libps2.h>
  15. #include <linux/types.h>
  16. #include "psmouse.h"
  17. #include "logips2pp.h"
  18. /* Logitech mouse types */
  19. #define PS2PP_KIND_WHEEL 1
  20. #define PS2PP_KIND_MX 2
  21. #define PS2PP_KIND_TP3 3
  22. #define PS2PP_KIND_TRACKMAN 4
  23. /* Logitech mouse features */
  24. #define PS2PP_WHEEL BIT(0)
  25. #define PS2PP_HWHEEL BIT(1)
  26. #define PS2PP_SIDE_BTN BIT(2)
  27. #define PS2PP_EXTRA_BTN BIT(3)
  28. #define PS2PP_TASK_BTN BIT(4)
  29. #define PS2PP_NAV_BTN BIT(5)
  30. struct ps2pp_info {
  31. u8 model;
  32. u8 kind;
  33. u16 features;
  34. };
  35. /*
  36. * Process a PS2++ or PS2T++ packet.
  37. */
  38. static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
  39. {
  40. struct input_dev *dev = psmouse->dev;
  41. u8 *packet = psmouse->packet;
  42. if (psmouse->pktcnt < 3)
  43. return PSMOUSE_GOOD_DATA;
  44. /*
  45. * Full packet accumulated, process it
  46. */
  47. if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
  48. /* Logitech extended packet */
  49. switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
  50. case 0x0d: /* Mouse extra info */
  51. input_report_rel(dev,
  52. packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
  53. -sign_extend32(packet[2], 3));
  54. input_report_key(dev, BTN_SIDE, packet[2] & BIT(4));
  55. input_report_key(dev, BTN_EXTRA, packet[2] & BIT(5));
  56. break;
  57. case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
  58. input_report_key(dev, BTN_SIDE, packet[2] & BIT(0));
  59. input_report_key(dev, BTN_EXTRA, packet[2] & BIT(1));
  60. input_report_key(dev, BTN_TASK, packet[2] & BIT(2));
  61. input_report_key(dev, BTN_BACK, packet[2] & BIT(3));
  62. input_report_key(dev, BTN_FORWARD, packet[2] & BIT(4));
  63. break;
  64. case 0x0f: /* TouchPad extra info */
  65. input_report_rel(dev,
  66. packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
  67. -sign_extend32(packet[2] >> 4, 3));
  68. packet[0] = packet[2] | BIT(3);
  69. break;
  70. default:
  71. psmouse_dbg(psmouse,
  72. "Received PS2++ packet #%x, but don't know how to handle.\n",
  73. (packet[1] >> 4) | (packet[0] & 0x30));
  74. break;
  75. }
  76. psmouse_report_standard_buttons(dev, packet[0]);
  77. } else {
  78. /* Standard PS/2 motion data */
  79. psmouse_report_standard_packet(dev, packet);
  80. }
  81. input_sync(dev);
  82. return PSMOUSE_FULL_PACKET;
  83. }
  84. /*
  85. * ps2pp_cmd() sends a PS2++ command, sliced into two bit
  86. * pieces through the SETRES command. This is needed to send extended
  87. * commands to mice on notebooks that try to understand the PS/2 protocol
  88. * Ugly.
  89. */
  90. static int ps2pp_cmd(struct psmouse *psmouse, u8 *param, u8 command)
  91. {
  92. int error;
  93. error = ps2_sliced_command(&psmouse->ps2dev, command);
  94. if (error)
  95. return error;
  96. error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300);
  97. if (error)
  98. return error;
  99. return 0;
  100. }
  101. /*
  102. * SmartScroll / CruiseControl for some newer Logitech mice Defaults to
  103. * enabled if we do nothing to it. Of course I put this in because I want it
  104. * disabled :P
  105. * 1 - enabled (if previously disabled, also default)
  106. * 0 - disabled
  107. */
  108. static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
  109. {
  110. struct ps2dev *ps2dev = &psmouse->ps2dev;
  111. u8 param[4];
  112. ps2pp_cmd(psmouse, param, 0x32);
  113. param[0] = 0;
  114. ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
  115. ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
  116. ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
  117. param[0] = smartscroll;
  118. ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
  119. }
  120. static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
  121. void *data, char *buf)
  122. {
  123. return sprintf(buf, "%d\n", psmouse->smartscroll);
  124. }
  125. static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
  126. const char *buf, size_t count)
  127. {
  128. unsigned int value;
  129. int err;
  130. err = kstrtouint(buf, 10, &value);
  131. if (err)
  132. return err;
  133. if (value > 1)
  134. return -EINVAL;
  135. ps2pp_set_smartscroll(psmouse, value);
  136. psmouse->smartscroll = value;
  137. return count;
  138. }
  139. PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
  140. ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
  141. /*
  142. * Support 800 dpi resolution _only_ if the user wants it (there are good
  143. * reasons to not use it even if the mouse supports it, and of course there are
  144. * also good reasons to use it, let the user decide).
  145. */
  146. static void ps2pp_set_resolution(struct psmouse *psmouse,
  147. unsigned int resolution)
  148. {
  149. if (resolution > 400) {
  150. struct ps2dev *ps2dev = &psmouse->ps2dev;
  151. u8 param = 3;
  152. ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
  153. ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
  154. ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
  155. ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
  156. psmouse->resolution = 800;
  157. } else
  158. psmouse_set_resolution(psmouse, resolution);
  159. }
  160. static void ps2pp_disconnect(struct psmouse *psmouse)
  161. {
  162. device_remove_file(&psmouse->ps2dev.serio->dev,
  163. &psmouse_attr_smartscroll.dattr);
  164. }
  165. static const struct ps2pp_info *get_model_info(unsigned char model)
  166. {
  167. static const struct ps2pp_info ps2pp_list[] = {
  168. { 1, 0, 0 }, /* Simple 2-button mouse */
  169. { 12, 0, PS2PP_SIDE_BTN},
  170. { 13, 0, 0 },
  171. { 15, PS2PP_KIND_MX, /* MX1000 */
  172. PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
  173. PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
  174. { 40, 0, PS2PP_SIDE_BTN },
  175. { 41, 0, PS2PP_SIDE_BTN },
  176. { 42, 0, PS2PP_SIDE_BTN },
  177. { 43, 0, PS2PP_SIDE_BTN },
  178. { 50, 0, 0 },
  179. { 51, 0, 0 },
  180. { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
  181. { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  182. { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */
  183. { 61, PS2PP_KIND_MX, /* MX700 */
  184. PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
  185. PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
  186. { 66, PS2PP_KIND_MX, /* MX3100 receiver */
  187. PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
  188. PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
  189. { 72, PS2PP_KIND_TRACKMAN, 0 }, /* T-CH11: TrackMan Marble */
  190. { 73, PS2PP_KIND_TRACKMAN, PS2PP_SIDE_BTN }, /* TrackMan FX */
  191. { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  192. { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  193. { 79, PS2PP_KIND_TRACKMAN, PS2PP_WHEEL }, /* TrackMan with wheel */
  194. { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
  195. { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  196. { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  197. { 85, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  198. { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  199. { 87, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  200. { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  201. { 96, 0, 0 },
  202. { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
  203. { 99, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
  204. { 100, PS2PP_KIND_MX, /* MX510 */
  205. PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
  206. PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
  207. { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */
  208. { 112, PS2PP_KIND_MX, /* MX500 */
  209. PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
  210. PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
  211. { 114, PS2PP_KIND_MX, /* MX310 */
  212. PS2PP_WHEEL | PS2PP_SIDE_BTN |
  213. PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
  214. };
  215. int i;
  216. for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++)
  217. if (model == ps2pp_list[i].model)
  218. return &ps2pp_list[i];
  219. return NULL;
  220. }
  221. /*
  222. * Set up input device's properties based on the detected mouse model.
  223. */
  224. static void ps2pp_set_model_properties(struct psmouse *psmouse,
  225. const struct ps2pp_info *model_info,
  226. bool using_ps2pp)
  227. {
  228. struct input_dev *input_dev = psmouse->dev;
  229. if (model_info->features & PS2PP_SIDE_BTN)
  230. input_set_capability(input_dev, EV_KEY, BTN_SIDE);
  231. if (model_info->features & PS2PP_EXTRA_BTN)
  232. input_set_capability(input_dev, EV_KEY, BTN_EXTRA);
  233. if (model_info->features & PS2PP_TASK_BTN)
  234. input_set_capability(input_dev, EV_KEY, BTN_TASK);
  235. if (model_info->features & PS2PP_NAV_BTN) {
  236. input_set_capability(input_dev, EV_KEY, BTN_FORWARD);
  237. input_set_capability(input_dev, EV_KEY, BTN_BACK);
  238. }
  239. if (model_info->features & PS2PP_WHEEL)
  240. input_set_capability(input_dev, EV_REL, REL_WHEEL);
  241. if (model_info->features & PS2PP_HWHEEL)
  242. input_set_capability(input_dev, EV_REL, REL_HWHEEL);
  243. switch (model_info->kind) {
  244. case PS2PP_KIND_WHEEL:
  245. psmouse->name = "Wheel Mouse";
  246. break;
  247. case PS2PP_KIND_MX:
  248. psmouse->name = "MX Mouse";
  249. break;
  250. case PS2PP_KIND_TP3:
  251. psmouse->name = "TouchPad 3";
  252. break;
  253. case PS2PP_KIND_TRACKMAN:
  254. psmouse->name = "TrackMan";
  255. break;
  256. default:
  257. /*
  258. * Set name to "Mouse" only when using PS2++,
  259. * otherwise let other protocols define suitable
  260. * name
  261. */
  262. if (using_ps2pp)
  263. psmouse->name = "Mouse";
  264. break;
  265. }
  266. }
  267. static int ps2pp_setup_protocol(struct psmouse *psmouse,
  268. const struct ps2pp_info *model_info)
  269. {
  270. int error;
  271. psmouse->protocol_handler = ps2pp_process_byte;
  272. psmouse->pktsize = 3;
  273. if (model_info->kind != PS2PP_KIND_TP3) {
  274. psmouse->set_resolution = ps2pp_set_resolution;
  275. psmouse->disconnect = ps2pp_disconnect;
  276. error = device_create_file(&psmouse->ps2dev.serio->dev,
  277. &psmouse_attr_smartscroll.dattr);
  278. if (error) {
  279. psmouse_err(psmouse,
  280. "failed to create smartscroll sysfs attribute, error: %d\n",
  281. error);
  282. return error;
  283. }
  284. }
  285. return 0;
  286. }
  287. /*
  288. * Logitech magic init. Detect whether the mouse is a Logitech one
  289. * and its exact model and try turning on extended protocol for ones
  290. * that support it.
  291. */
  292. int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
  293. {
  294. struct ps2dev *ps2dev = &psmouse->ps2dev;
  295. const struct ps2pp_info *model_info;
  296. u8 param[4];
  297. u8 model, buttons;
  298. bool use_ps2pp = false;
  299. int error;
  300. param[0] = 0;
  301. ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
  302. ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
  303. ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
  304. ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
  305. param[1] = 0;
  306. ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
  307. model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
  308. buttons = param[1];
  309. if (!model || !buttons)
  310. return -ENXIO;
  311. model_info = get_model_info(model);
  312. if (model_info) {
  313. /*
  314. * Do Logitech PS2++ / PS2T++ magic init.
  315. */
  316. if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
  317. /* Unprotect RAM */
  318. param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
  319. ps2_command(ps2dev, param, 0x30d1);
  320. /* Enable features */
  321. param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
  322. ps2_command(ps2dev, param, 0x30d1);
  323. /* Enable PS2++ */
  324. param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
  325. ps2_command(ps2dev, param, 0x30d1);
  326. param[0] = 0;
  327. if (!ps2_command(ps2dev, param, 0x13d1) &&
  328. param[0] == 0x06 && param[1] == 0x00 &&
  329. param[2] == 0x14) {
  330. use_ps2pp = true;
  331. }
  332. } else {
  333. param[0] = param[1] = param[2] = 0;
  334. ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
  335. ps2pp_cmd(psmouse, param, 0xDB);
  336. if ((param[0] & 0x78) == 0x48 &&
  337. (param[1] & 0xf3) == 0xc2 &&
  338. (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
  339. ps2pp_set_smartscroll(psmouse, false);
  340. use_ps2pp = true;
  341. }
  342. }
  343. } else {
  344. psmouse_warn(psmouse,
  345. "Detected unknown Logitech mouse model %d\n",
  346. model);
  347. }
  348. if (set_properties) {
  349. psmouse->vendor = "Logitech";
  350. psmouse->model = model;
  351. if (use_ps2pp) {
  352. error = ps2pp_setup_protocol(psmouse, model_info);
  353. if (error)
  354. return error;
  355. }
  356. if (buttons >= 3)
  357. input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
  358. if (model_info)
  359. ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
  360. }
  361. return use_ps2pp ? 0 : -ENXIO;
  362. }