byd.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*
  2. * BYD TouchPad PS/2 mouse driver
  3. *
  4. * Copyright (C) 2015 Chris Diamand <chris@diamand.org>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/input.h>
  12. #include <linux/libps2.h>
  13. #include <linux/serio.h>
  14. #include <linux/slab.h>
  15. #include "psmouse.h"
  16. #include "byd.h"
  17. /* PS2 Bits */
  18. #define PS2_Y_OVERFLOW BIT_MASK(7)
  19. #define PS2_X_OVERFLOW BIT_MASK(6)
  20. #define PS2_Y_SIGN BIT_MASK(5)
  21. #define PS2_X_SIGN BIT_MASK(4)
  22. #define PS2_ALWAYS_1 BIT_MASK(3)
  23. #define PS2_MIDDLE BIT_MASK(2)
  24. #define PS2_RIGHT BIT_MASK(1)
  25. #define PS2_LEFT BIT_MASK(0)
  26. /*
  27. * BYD pad constants
  28. */
  29. /*
  30. * True device resolution is unknown, however experiments show the
  31. * resolution is about 111 units/mm.
  32. * Absolute coordinate packets are in the range 0-255 for both X and Y
  33. * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in
  34. * the right ballpark given the touchpad's physical dimensions and estimate
  35. * resolution per spec sheet, device active area dimensions are
  36. * 101.6 x 60.1 mm.
  37. */
  38. #define BYD_PAD_WIDTH 11264
  39. #define BYD_PAD_HEIGHT 6656
  40. #define BYD_PAD_RESOLUTION 111
  41. /*
  42. * Given the above dimensions, relative packets velocity is in multiples of
  43. * 1 unit / 11 milliseconds. We use this dt to estimate distance traveled
  44. */
  45. #define BYD_DT 11
  46. /* Time in jiffies used to timeout various touch events (64 ms) */
  47. #define BYD_TOUCH_TIMEOUT msecs_to_jiffies(64)
  48. /* BYD commands reverse engineered from windows driver */
  49. /*
  50. * Swipe gesture from off-pad to on-pad
  51. * 0 : disable
  52. * 1 : enable
  53. */
  54. #define BYD_CMD_SET_OFFSCREEN_SWIPE 0x10cc
  55. /*
  56. * Tap and drag delay time
  57. * 0 : disable
  58. * 1 - 8 : least to most delay
  59. */
  60. #define BYD_CMD_SET_TAP_DRAG_DELAY_TIME 0x10cf
  61. /*
  62. * Physical buttons function mapping
  63. * 0 : enable
  64. * 4 : normal
  65. * 5 : left button custom command
  66. * 6 : right button custom command
  67. * 8 : disable
  68. */
  69. #define BYD_CMD_SET_PHYSICAL_BUTTONS 0x10d0
  70. /*
  71. * Absolute mode (1 byte X/Y resolution)
  72. * 0 : disable
  73. * 2 : enable
  74. */
  75. #define BYD_CMD_SET_ABSOLUTE_MODE 0x10d1
  76. /*
  77. * Two finger scrolling
  78. * 1 : vertical
  79. * 2 : horizontal
  80. * 3 : vertical + horizontal
  81. * 4 : disable
  82. */
  83. #define BYD_CMD_SET_TWO_FINGER_SCROLL 0x10d2
  84. /*
  85. * Handedness
  86. * 1 : right handed
  87. * 2 : left handed
  88. */
  89. #define BYD_CMD_SET_HANDEDNESS 0x10d3
  90. /*
  91. * Tap to click
  92. * 1 : enable
  93. * 2 : disable
  94. */
  95. #define BYD_CMD_SET_TAP 0x10d4
  96. /*
  97. * Tap and drag
  98. * 1 : tap and hold to drag
  99. * 2 : tap and hold to drag + lock
  100. * 3 : disable
  101. */
  102. #define BYD_CMD_SET_TAP_DRAG 0x10d5
  103. /*
  104. * Touch sensitivity
  105. * 1 - 7 : least to most sensitive
  106. */
  107. #define BYD_CMD_SET_TOUCH_SENSITIVITY 0x10d6
  108. /*
  109. * One finger scrolling
  110. * 1 : vertical
  111. * 2 : horizontal
  112. * 3 : vertical + horizontal
  113. * 4 : disable
  114. */
  115. #define BYD_CMD_SET_ONE_FINGER_SCROLL 0x10d7
  116. /*
  117. * One finger scrolling function
  118. * 1 : free scrolling
  119. * 2 : edge motion
  120. * 3 : free scrolling + edge motion
  121. * 4 : disable
  122. */
  123. #define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC 0x10d8
  124. /*
  125. * Sliding speed
  126. * 1 - 5 : slowest to fastest
  127. */
  128. #define BYD_CMD_SET_SLIDING_SPEED 0x10da
  129. /*
  130. * Edge motion
  131. * 1 : disable
  132. * 2 : enable when dragging
  133. * 3 : enable when dragging and pointing
  134. */
  135. #define BYD_CMD_SET_EDGE_MOTION 0x10db
  136. /*
  137. * Left edge region size
  138. * 0 - 7 : smallest to largest width
  139. */
  140. #define BYD_CMD_SET_LEFT_EDGE_REGION 0x10dc
  141. /*
  142. * Top edge region size
  143. * 0 - 9 : smallest to largest height
  144. */
  145. #define BYD_CMD_SET_TOP_EDGE_REGION 0x10dd
  146. /*
  147. * Disregard palm press as clicks
  148. * 1 - 6 : smallest to largest
  149. */
  150. #define BYD_CMD_SET_PALM_CHECK 0x10de
  151. /*
  152. * Right edge region size
  153. * 0 - 7 : smallest to largest width
  154. */
  155. #define BYD_CMD_SET_RIGHT_EDGE_REGION 0x10df
  156. /*
  157. * Bottom edge region size
  158. * 0 - 9 : smallest to largest height
  159. */
  160. #define BYD_CMD_SET_BOTTOM_EDGE_REGION 0x10e1
  161. /*
  162. * Multitouch gestures
  163. * 1 : enable
  164. * 2 : disable
  165. */
  166. #define BYD_CMD_SET_MULTITOUCH 0x10e3
  167. /*
  168. * Edge motion speed
  169. * 0 : control with finger pressure
  170. * 1 - 9 : slowest to fastest
  171. */
  172. #define BYD_CMD_SET_EDGE_MOTION_SPEED 0x10e4
  173. /*
  174. * Two finger scolling function
  175. * 0 : free scrolling
  176. * 1 : free scrolling (with momentum)
  177. * 2 : edge motion
  178. * 3 : free scrolling (with momentum) + edge motion
  179. * 4 : disable
  180. */
  181. #define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC 0x10e5
  182. /*
  183. * The touchpad generates a mixture of absolute and relative packets, indicated
  184. * by the the last byte of each packet being set to one of the following:
  185. */
  186. #define BYD_PACKET_ABSOLUTE 0xf8
  187. #define BYD_PACKET_RELATIVE 0x00
  188. /* Multitouch gesture packets */
  189. #define BYD_PACKET_PINCH_IN 0xd8
  190. #define BYD_PACKET_PINCH_OUT 0x28
  191. #define BYD_PACKET_ROTATE_CLOCKWISE 0x29
  192. #define BYD_PACKET_ROTATE_ANTICLOCKWISE 0xd7
  193. #define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT 0x2a
  194. #define BYD_PACKET_TWO_FINGER_SCROLL_DOWN 0x2b
  195. #define BYD_PACKET_TWO_FINGER_SCROLL_UP 0xd5
  196. #define BYD_PACKET_TWO_FINGER_SCROLL_LEFT 0xd6
  197. #define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT 0x2c
  198. #define BYD_PACKET_THREE_FINGER_SWIPE_DOWN 0x2d
  199. #define BYD_PACKET_THREE_FINGER_SWIPE_UP 0xd3
  200. #define BYD_PACKET_THREE_FINGER_SWIPE_LEFT 0xd4
  201. #define BYD_PACKET_FOUR_FINGER_DOWN 0x33
  202. #define BYD_PACKET_FOUR_FINGER_UP 0xcd
  203. #define BYD_PACKET_REGION_SCROLL_RIGHT 0x35
  204. #define BYD_PACKET_REGION_SCROLL_DOWN 0x36
  205. #define BYD_PACKET_REGION_SCROLL_UP 0xca
  206. #define BYD_PACKET_REGION_SCROLL_LEFT 0xcb
  207. #define BYD_PACKET_RIGHT_CORNER_CLICK 0xd2
  208. #define BYD_PACKET_LEFT_CORNER_CLICK 0x2e
  209. #define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK 0x2f
  210. #define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT 0x37
  211. #define BYD_PACKET_ONTO_PAD_SWIPE_DOWN 0x30
  212. #define BYD_PACKET_ONTO_PAD_SWIPE_UP 0xd0
  213. #define BYD_PACKET_ONTO_PAD_SWIPE_LEFT 0xc9
  214. struct byd_data {
  215. struct timer_list timer;
  216. s32 abs_x;
  217. s32 abs_y;
  218. typeof(jiffies) last_touch_time;
  219. bool btn_left;
  220. bool btn_right;
  221. bool touch;
  222. };
  223. static void byd_report_input(struct psmouse *psmouse)
  224. {
  225. struct byd_data *priv = psmouse->private;
  226. struct input_dev *dev = psmouse->dev;
  227. input_report_key(dev, BTN_TOUCH, priv->touch);
  228. input_report_key(dev, BTN_TOOL_FINGER, priv->touch);
  229. input_report_abs(dev, ABS_X, priv->abs_x);
  230. input_report_abs(dev, ABS_Y, priv->abs_y);
  231. input_report_key(dev, BTN_LEFT, priv->btn_left);
  232. input_report_key(dev, BTN_RIGHT, priv->btn_right);
  233. input_sync(dev);
  234. }
  235. static void byd_clear_touch(unsigned long data)
  236. {
  237. struct psmouse *psmouse = (struct psmouse *)data;
  238. struct byd_data *priv = psmouse->private;
  239. serio_pause_rx(psmouse->ps2dev.serio);
  240. priv->touch = false;
  241. byd_report_input(psmouse);
  242. serio_continue_rx(psmouse->ps2dev.serio);
  243. /*
  244. * Move cursor back to center of pad when we lose touch - this
  245. * specifically improves user experience when moving cursor with one
  246. * finger, and pressing a button with another.
  247. */
  248. priv->abs_x = BYD_PAD_WIDTH / 2;
  249. priv->abs_y = BYD_PAD_HEIGHT / 2;
  250. }
  251. static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
  252. {
  253. struct byd_data *priv = psmouse->private;
  254. u8 *pkt = psmouse->packet;
  255. if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) {
  256. psmouse_warn(psmouse, "Always_1 bit not 1. pkt[0] = %02x\n",
  257. pkt[0]);
  258. return PSMOUSE_BAD_DATA;
  259. }
  260. if (psmouse->pktcnt < psmouse->pktsize)
  261. return PSMOUSE_GOOD_DATA;
  262. /* Otherwise, a full packet has been received */
  263. switch (pkt[3]) {
  264. case BYD_PACKET_ABSOLUTE:
  265. /* Only use absolute packets for the start of movement. */
  266. if (!priv->touch) {
  267. /* needed to detect tap */
  268. typeof(jiffies) tap_time =
  269. priv->last_touch_time + BYD_TOUCH_TIMEOUT;
  270. priv->touch = time_after(jiffies, tap_time);
  271. /* init abs position */
  272. priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256);
  273. priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256);
  274. }
  275. break;
  276. case BYD_PACKET_RELATIVE: {
  277. /* Standard packet */
  278. /* Sign-extend if a sign bit is set. */
  279. u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0;
  280. u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0;
  281. s32 dx = signx | (int) pkt[1];
  282. s32 dy = signy | (int) pkt[2];
  283. /* Update position based on velocity */
  284. priv->abs_x += dx * BYD_DT;
  285. priv->abs_y -= dy * BYD_DT;
  286. priv->touch = true;
  287. break;
  288. }
  289. default:
  290. psmouse_warn(psmouse,
  291. "Unrecognized Z: pkt = %02x %02x %02x %02x\n",
  292. psmouse->packet[0], psmouse->packet[1],
  293. psmouse->packet[2], psmouse->packet[3]);
  294. return PSMOUSE_BAD_DATA;
  295. }
  296. priv->btn_left = pkt[0] & PS2_LEFT;
  297. priv->btn_right = pkt[0] & PS2_RIGHT;
  298. byd_report_input(psmouse);
  299. /* Reset time since last touch. */
  300. if (priv->touch) {
  301. priv->last_touch_time = jiffies;
  302. mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT);
  303. }
  304. return PSMOUSE_FULL_PACKET;
  305. }
  306. static int byd_reset_touchpad(struct psmouse *psmouse)
  307. {
  308. struct ps2dev *ps2dev = &psmouse->ps2dev;
  309. u8 param[4];
  310. size_t i;
  311. const struct {
  312. u16 command;
  313. u8 arg;
  314. } seq[] = {
  315. /*
  316. * Intellimouse initialization sequence, to get 4-byte instead
  317. * of 3-byte packets.
  318. */
  319. { PSMOUSE_CMD_SETRATE, 0xC8 },
  320. { PSMOUSE_CMD_SETRATE, 0x64 },
  321. { PSMOUSE_CMD_SETRATE, 0x50 },
  322. { PSMOUSE_CMD_GETID, 0 },
  323. { PSMOUSE_CMD_ENABLE, 0 },
  324. /*
  325. * BYD-specific initialization, which enables absolute mode and
  326. * (if desired), the touchpad's built-in gesture detection.
  327. */
  328. { 0x10E2, 0x00 },
  329. { 0x10E0, 0x02 },
  330. /* The touchpad should reply with 4 seemingly-random bytes */
  331. { 0x14E0, 0x01 },
  332. /* Pairs of parameters and values. */
  333. { BYD_CMD_SET_HANDEDNESS, 0x01 },
  334. { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 },
  335. { BYD_CMD_SET_TAP, 0x02 },
  336. { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 },
  337. { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 },
  338. { BYD_CMD_SET_EDGE_MOTION, 0x01 },
  339. { BYD_CMD_SET_PALM_CHECK, 0x00 },
  340. { BYD_CMD_SET_MULTITOUCH, 0x02 },
  341. { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 },
  342. { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 },
  343. { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 },
  344. { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 },
  345. { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 },
  346. { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 },
  347. { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 },
  348. /* Finalize initialization. */
  349. { 0x10E0, 0x00 },
  350. { 0x10E2, 0x01 },
  351. };
  352. for (i = 0; i < ARRAY_SIZE(seq); ++i) {
  353. memset(param, 0, sizeof(param));
  354. param[0] = seq[i].arg;
  355. if (ps2_command(ps2dev, param, seq[i].command))
  356. return -EIO;
  357. }
  358. psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
  359. return 0;
  360. }
  361. static int byd_reconnect(struct psmouse *psmouse)
  362. {
  363. int retry = 0, error = 0;
  364. psmouse_dbg(psmouse, "Reconnect\n");
  365. do {
  366. psmouse_reset(psmouse);
  367. if (retry)
  368. ssleep(1);
  369. error = byd_detect(psmouse, 0);
  370. } while (error && ++retry < 3);
  371. if (error)
  372. return error;
  373. psmouse_dbg(psmouse, "Reconnected after %d attempts\n", retry);
  374. error = byd_reset_touchpad(psmouse);
  375. if (error) {
  376. psmouse_err(psmouse, "Unable to initialize device\n");
  377. return error;
  378. }
  379. return 0;
  380. }
  381. static void byd_disconnect(struct psmouse *psmouse)
  382. {
  383. struct byd_data *priv = psmouse->private;
  384. if (priv) {
  385. del_timer(&priv->timer);
  386. kfree(psmouse->private);
  387. psmouse->private = NULL;
  388. }
  389. }
  390. int byd_detect(struct psmouse *psmouse, bool set_properties)
  391. {
  392. struct ps2dev *ps2dev = &psmouse->ps2dev;
  393. u8 param[4] = {0x03, 0x00, 0x00, 0x00};
  394. if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
  395. return -1;
  396. if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
  397. return -1;
  398. if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
  399. return -1;
  400. if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
  401. return -1;
  402. if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
  403. return -1;
  404. if (param[1] != 0x03 || param[2] != 0x64)
  405. return -ENODEV;
  406. psmouse_dbg(psmouse, "BYD touchpad detected\n");
  407. if (set_properties) {
  408. psmouse->vendor = "BYD";
  409. psmouse->name = "TouchPad";
  410. }
  411. return 0;
  412. }
  413. int byd_init(struct psmouse *psmouse)
  414. {
  415. struct input_dev *dev = psmouse->dev;
  416. struct byd_data *priv;
  417. if (psmouse_reset(psmouse))
  418. return -EIO;
  419. if (byd_reset_touchpad(psmouse))
  420. return -EIO;
  421. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  422. if (!priv)
  423. return -ENOMEM;
  424. memset(priv, 0, sizeof(*priv));
  425. setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse);
  426. psmouse->private = priv;
  427. psmouse->disconnect = byd_disconnect;
  428. psmouse->reconnect = byd_reconnect;
  429. psmouse->protocol_handler = byd_process_byte;
  430. psmouse->pktsize = 4;
  431. psmouse->resync_time = 0;
  432. __set_bit(INPUT_PROP_POINTER, dev->propbit);
  433. /* Touchpad */
  434. __set_bit(BTN_TOUCH, dev->keybit);
  435. __set_bit(BTN_TOOL_FINGER, dev->keybit);
  436. /* Buttons */
  437. __set_bit(BTN_LEFT, dev->keybit);
  438. __set_bit(BTN_RIGHT, dev->keybit);
  439. __clear_bit(BTN_MIDDLE, dev->keybit);
  440. /* Absolute position */
  441. __set_bit(EV_ABS, dev->evbit);
  442. input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0);
  443. input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0);
  444. input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION);
  445. input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION);
  446. /* No relative support */
  447. __clear_bit(EV_REL, dev->evbit);
  448. __clear_bit(REL_X, dev->relbit);
  449. __clear_bit(REL_Y, dev->relbit);
  450. return 0;
  451. }