cypress_ps2.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Cypress Trackpad PS/2 mouse driver
  4. *
  5. * Copyright (c) 2012 Cypress Semiconductor Corporation.
  6. *
  7. * Author:
  8. * Dudley Du <dudl@cypress.com>
  9. *
  10. * Additional contributors include:
  11. * Kamal Mostafa <kamal@canonical.com>
  12. * Kyle Fazzari <git@status.e4ward.com>
  13. */
  14. #include <linux/module.h>
  15. #include <linux/kernel.h>
  16. #include <linux/slab.h>
  17. #include <linux/serio.h>
  18. #include <linux/libps2.h>
  19. #include <linux/input.h>
  20. #include <linux/input/mt.h>
  21. #include <linux/sched.h>
  22. #include <linux/wait.h>
  23. #include "cypress_ps2.h"
  24. #undef CYTP_DEBUG_VERBOSE /* define this and DEBUG for more verbose dump */
  25. static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
  26. {
  27. struct cytp_data *cytp = psmouse->private;
  28. cytp->pkt_size = n;
  29. }
  30. static const u8 cytp_rate[] = {10, 20, 40, 60, 100, 200};
  31. static const u8 cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
  32. static int cypress_ps2_sendbyte(struct psmouse *psmouse, u8 cmd)
  33. {
  34. struct ps2dev *ps2dev = &psmouse->ps2dev;
  35. int error;
  36. error = ps2_sendbyte(ps2dev, cmd, CYTP_CMD_TIMEOUT);
  37. if (error) {
  38. psmouse_dbg(psmouse,
  39. "sending command 0x%02x failed, resp 0x%02x, error %d\n",
  40. cmd, ps2dev->nak, error);
  41. return error;
  42. }
  43. #ifdef CYTP_DEBUG_VERBOSE
  44. psmouse_dbg(psmouse, "sending command 0x%02x succeeded\n", cmd);
  45. #endif
  46. return 0;
  47. }
  48. static int cypress_ps2_ext_cmd(struct psmouse *psmouse, u8 prefix, u8 nibble)
  49. {
  50. struct ps2dev *ps2dev = &psmouse->ps2dev;
  51. int tries = CYTP_PS2_CMD_TRIES;
  52. int rc;
  53. ps2_begin_command(ps2dev);
  54. do {
  55. /*
  56. * Send extension command byte (0xE8 or 0xF3).
  57. * If sending the command fails, send recovery command
  58. * to make the device return to the ready state.
  59. */
  60. rc = cypress_ps2_sendbyte(psmouse, prefix);
  61. if (rc == -EAGAIN) {
  62. rc = cypress_ps2_sendbyte(psmouse, 0x00);
  63. if (rc == -EAGAIN)
  64. rc = cypress_ps2_sendbyte(psmouse, 0x0a);
  65. }
  66. if (!rc) {
  67. rc = cypress_ps2_sendbyte(psmouse, nibble);
  68. if (rc == -EAGAIN)
  69. rc = cypress_ps2_sendbyte(psmouse, nibble);
  70. if (!rc)
  71. break;
  72. }
  73. } while (--tries > 0);
  74. ps2_end_command(ps2dev);
  75. return rc;
  76. }
  77. static bool cypress_verify_cmd_state(struct psmouse *psmouse, u8 cmd, u8* param)
  78. {
  79. bool rate_match = false;
  80. bool resolution_match = false;
  81. int i;
  82. /* callers will do further checking. */
  83. if (cmd == CYTP_CMD_READ_CYPRESS_ID ||
  84. cmd == CYTP_CMD_STANDARD_MODE ||
  85. cmd == CYTP_CMD_READ_TP_METRICS)
  86. return true;
  87. if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID &&
  88. (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) {
  89. for (i = 0; i < sizeof(cytp_resolution); i++)
  90. if (cytp_resolution[i] == param[1])
  91. resolution_match = true;
  92. for (i = 0; i < sizeof(cytp_rate); i++)
  93. if (cytp_rate[i] == param[2])
  94. rate_match = true;
  95. if (resolution_match && rate_match)
  96. return true;
  97. }
  98. psmouse_dbg(psmouse, "verify cmd state failed.\n");
  99. return false;
  100. }
  101. static int cypress_send_ext_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
  102. {
  103. u8 cmd_prefix = PSMOUSE_CMD_SETRES & 0xff;
  104. unsigned int resp_size = cmd == CYTP_CMD_READ_TP_METRICS ? 8 : 3;
  105. unsigned int ps2_cmd = (PSMOUSE_CMD_GETINFO & 0xff) | (resp_size << 8);
  106. int tries = CYTP_PS2_CMD_TRIES;
  107. int error;
  108. psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n",
  109. cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd),
  110. DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd));
  111. do {
  112. cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_DD(cmd));
  113. cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_CC(cmd));
  114. cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_BB(cmd));
  115. cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_AA(cmd));
  116. error = ps2_command(&psmouse->ps2dev, param, ps2_cmd);
  117. if (error) {
  118. psmouse_dbg(psmouse, "Command 0x%02x failed: %d\n",
  119. cmd, error);
  120. } else {
  121. psmouse_dbg(psmouse,
  122. "Command 0x%02x response data (0x): %*ph\n",
  123. cmd, resp_size, param);
  124. if (cypress_verify_cmd_state(psmouse, cmd, param))
  125. return 0;
  126. }
  127. } while (--tries > 0);
  128. return -EIO;
  129. }
  130. int cypress_detect(struct psmouse *psmouse, bool set_properties)
  131. {
  132. u8 param[3];
  133. if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
  134. return -ENODEV;
  135. /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
  136. if (param[0] != 0x33 || param[1] != 0xCC)
  137. return -ENODEV;
  138. if (set_properties) {
  139. psmouse->vendor = "Cypress";
  140. psmouse->name = "Trackpad";
  141. }
  142. return 0;
  143. }
  144. static int cypress_read_fw_version(struct psmouse *psmouse)
  145. {
  146. struct cytp_data *cytp = psmouse->private;
  147. u8 param[3];
  148. if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
  149. return -ENODEV;
  150. /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
  151. if (param[0] != 0x33 || param[1] != 0xCC)
  152. return -ENODEV;
  153. cytp->fw_version = param[2] & FW_VERSION_MASX;
  154. cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0;
  155. /*
  156. * Trackpad fw_version 11 (in Dell XPS12) yields a bogus response to
  157. * CYTP_CMD_READ_TP_METRICS so do not try to use it. LP: #1103594.
  158. */
  159. if (cytp->fw_version >= 11)
  160. cytp->tp_metrics_supported = 0;
  161. psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version);
  162. psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n",
  163. cytp->tp_metrics_supported);
  164. return 0;
  165. }
  166. static int cypress_read_tp_metrics(struct psmouse *psmouse)
  167. {
  168. struct cytp_data *cytp = psmouse->private;
  169. u8 param[8];
  170. /* set default values for tp metrics. */
  171. cytp->tp_width = CYTP_DEFAULT_WIDTH;
  172. cytp->tp_high = CYTP_DEFAULT_HIGH;
  173. cytp->tp_max_abs_x = CYTP_ABS_MAX_X;
  174. cytp->tp_max_abs_y = CYTP_ABS_MAX_Y;
  175. cytp->tp_min_pressure = CYTP_MIN_PRESSURE;
  176. cytp->tp_max_pressure = CYTP_MAX_PRESSURE;
  177. cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
  178. cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
  179. if (!cytp->tp_metrics_supported)
  180. return 0;
  181. memset(param, 0, sizeof(param));
  182. if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) {
  183. /* Update trackpad parameters. */
  184. cytp->tp_max_abs_x = (param[1] << 8) | param[0];
  185. cytp->tp_max_abs_y = (param[3] << 8) | param[2];
  186. cytp->tp_min_pressure = param[4];
  187. cytp->tp_max_pressure = param[5];
  188. }
  189. if (!cytp->tp_max_pressure ||
  190. cytp->tp_max_pressure < cytp->tp_min_pressure ||
  191. !cytp->tp_width || !cytp->tp_high ||
  192. !cytp->tp_max_abs_x ||
  193. cytp->tp_max_abs_x < cytp->tp_width ||
  194. !cytp->tp_max_abs_y ||
  195. cytp->tp_max_abs_y < cytp->tp_high)
  196. return -EINVAL;
  197. cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
  198. cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
  199. #ifdef CYTP_DEBUG_VERBOSE
  200. psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n");
  201. psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width);
  202. psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high);
  203. psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x);
  204. psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y);
  205. psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure);
  206. psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure);
  207. psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x);
  208. psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y);
  209. psmouse_dbg(psmouse, "tp_type_APA = %d\n",
  210. (param[6] & TP_METRICS_BIT_APA) ? 1 : 0);
  211. psmouse_dbg(psmouse, "tp_type_MTG = %d\n",
  212. (param[6] & TP_METRICS_BIT_MTG) ? 1 : 0);
  213. psmouse_dbg(psmouse, "tp_palm = %d\n",
  214. (param[6] & TP_METRICS_BIT_PALM) ? 1 : 0);
  215. psmouse_dbg(psmouse, "tp_stubborn = %d\n",
  216. (param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0);
  217. psmouse_dbg(psmouse, "tp_1f_jitter = %d\n",
  218. (param[6] & TP_METRICS_BIT_1F_JITTER) >> 2);
  219. psmouse_dbg(psmouse, "tp_2f_jitter = %d\n",
  220. (param[6] & TP_METRICS_BIT_2F_JITTER) >> 4);
  221. psmouse_dbg(psmouse, "tp_1f_spike = %d\n",
  222. param[7] & TP_METRICS_BIT_1F_SPIKE);
  223. psmouse_dbg(psmouse, "tp_2f_spike = %d\n",
  224. (param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2);
  225. psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n",
  226. (param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4);
  227. #endif
  228. return 0;
  229. }
  230. static int cypress_query_hardware(struct psmouse *psmouse)
  231. {
  232. int error;
  233. error = cypress_read_fw_version(psmouse);
  234. if (error)
  235. return error;
  236. error = cypress_read_tp_metrics(psmouse);
  237. if (error)
  238. return error;
  239. return 0;
  240. }
  241. static int cypress_set_absolute_mode(struct psmouse *psmouse)
  242. {
  243. struct cytp_data *cytp = psmouse->private;
  244. u8 param[3];
  245. int error;
  246. error = cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE,
  247. param);
  248. if (error)
  249. return error;
  250. cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
  251. | CYTP_BIT_ABS_PRESSURE;
  252. cypress_set_packet_size(psmouse, 5);
  253. return 0;
  254. }
  255. /*
  256. * Reset trackpad device.
  257. * This is also the default mode when trackpad powered on.
  258. */
  259. static void cypress_reset(struct psmouse *psmouse)
  260. {
  261. struct cytp_data *cytp = psmouse->private;
  262. cytp->mode = 0;
  263. psmouse_reset(psmouse);
  264. }
  265. static int cypress_set_input_params(struct input_dev *input,
  266. struct cytp_data *cytp)
  267. {
  268. int error;
  269. if (!cytp->tp_res_x || !cytp->tp_res_y)
  270. return -EINVAL;
  271. __set_bit(EV_ABS, input->evbit);
  272. input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0);
  273. input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0);
  274. input_set_abs_params(input, ABS_PRESSURE,
  275. cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0);
  276. input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
  277. /* finger position */
  278. input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0);
  279. input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
  280. input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
  281. error = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
  282. INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK);
  283. if (error)
  284. return error;
  285. __set_bit(INPUT_PROP_SEMI_MT, input->propbit);
  286. input_abs_set_res(input, ABS_X, cytp->tp_res_x);
  287. input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
  288. input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x);
  289. input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y);
  290. __set_bit(BTN_TOUCH, input->keybit);
  291. __set_bit(BTN_TOOL_FINGER, input->keybit);
  292. __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
  293. __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
  294. __set_bit(BTN_TOOL_QUADTAP, input->keybit);
  295. __set_bit(BTN_TOOL_QUINTTAP, input->keybit);
  296. __clear_bit(EV_REL, input->evbit);
  297. __clear_bit(REL_X, input->relbit);
  298. __clear_bit(REL_Y, input->relbit);
  299. __set_bit(EV_KEY, input->evbit);
  300. __set_bit(BTN_LEFT, input->keybit);
  301. __set_bit(BTN_RIGHT, input->keybit);
  302. __set_bit(BTN_MIDDLE, input->keybit);
  303. return 0;
  304. }
  305. static int cypress_get_finger_count(u8 header_byte)
  306. {
  307. u8 bits6_7;
  308. int finger_count;
  309. bits6_7 = header_byte >> 6;
  310. finger_count = bits6_7 & 0x03;
  311. if (finger_count == 1)
  312. return 1;
  313. if (header_byte & ABS_HSCROLL_BIT) {
  314. /* HSCROLL gets added on to 0 finger count. */
  315. switch (finger_count) {
  316. case 0: return 4;
  317. case 2: return 5;
  318. default:
  319. /* Invalid contact (e.g. palm). Ignore it. */
  320. return 0;
  321. }
  322. }
  323. return finger_count;
  324. }
  325. static int cypress_parse_packet(struct psmouse *psmouse,
  326. struct cytp_data *cytp,
  327. struct cytp_report_data *report_data)
  328. {
  329. u8 *packet = psmouse->packet;
  330. u8 header_byte = packet[0];
  331. memset(report_data, 0, sizeof(struct cytp_report_data));
  332. report_data->contact_cnt = cypress_get_finger_count(header_byte);
  333. report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
  334. if (report_data->contact_cnt == 1) {
  335. report_data->contacts[0].x =
  336. ((packet[1] & 0x70) << 4) | packet[2];
  337. report_data->contacts[0].y =
  338. ((packet[1] & 0x07) << 8) | packet[3];
  339. if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
  340. report_data->contacts[0].z = packet[4];
  341. } else if (report_data->contact_cnt >= 2) {
  342. report_data->contacts[0].x =
  343. ((packet[1] & 0x70) << 4) | packet[2];
  344. report_data->contacts[0].y =
  345. ((packet[1] & 0x07) << 8) | packet[3];
  346. if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
  347. report_data->contacts[0].z = packet[4];
  348. report_data->contacts[1].x =
  349. ((packet[5] & 0xf0) << 4) | packet[6];
  350. report_data->contacts[1].y =
  351. ((packet[5] & 0x0f) << 8) | packet[7];
  352. if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
  353. report_data->contacts[1].z = report_data->contacts[0].z;
  354. }
  355. report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
  356. report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0;
  357. /*
  358. * This is only true if one of the mouse buttons were tapped. Make
  359. * sure it doesn't turn into a click. The regular tap-to-click
  360. * functionality will handle that on its own. If we don't do this,
  361. * disabling tap-to-click won't affect the mouse button zones.
  362. */
  363. if (report_data->tap)
  364. report_data->left = 0;
  365. #ifdef CYTP_DEBUG_VERBOSE
  366. {
  367. int i;
  368. int n = report_data->contact_cnt;
  369. psmouse_dbg(psmouse, "Dump parsed report data as below:\n");
  370. psmouse_dbg(psmouse, "contact_cnt = %d\n",
  371. report_data->contact_cnt);
  372. if (n > CYTP_MAX_MT_SLOTS)
  373. n = CYTP_MAX_MT_SLOTS;
  374. for (i = 0; i < n; i++)
  375. psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i,
  376. report_data->contacts[i].x,
  377. report_data->contacts[i].y,
  378. report_data->contacts[i].z);
  379. psmouse_dbg(psmouse, "left = %d\n", report_data->left);
  380. psmouse_dbg(psmouse, "right = %d\n", report_data->right);
  381. psmouse_dbg(psmouse, "middle = %d\n", report_data->middle);
  382. }
  383. #endif
  384. return 0;
  385. }
  386. static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
  387. {
  388. int i;
  389. struct input_dev *input = psmouse->dev;
  390. struct cytp_data *cytp = psmouse->private;
  391. struct cytp_report_data report_data;
  392. struct cytp_contact *contact;
  393. struct input_mt_pos pos[CYTP_MAX_MT_SLOTS];
  394. int slots[CYTP_MAX_MT_SLOTS];
  395. int n;
  396. cypress_parse_packet(psmouse, cytp, &report_data);
  397. n = report_data.contact_cnt;
  398. if (n > CYTP_MAX_MT_SLOTS)
  399. n = CYTP_MAX_MT_SLOTS;
  400. for (i = 0; i < n; i++) {
  401. contact = &report_data.contacts[i];
  402. pos[i].x = contact->x;
  403. pos[i].y = contact->y;
  404. }
  405. input_mt_assign_slots(input, slots, pos, n, 0);
  406. for (i = 0; i < n; i++) {
  407. contact = &report_data.contacts[i];
  408. input_mt_slot(input, slots[i]);
  409. input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
  410. input_report_abs(input, ABS_MT_POSITION_X, contact->x);
  411. input_report_abs(input, ABS_MT_POSITION_Y, contact->y);
  412. input_report_abs(input, ABS_MT_PRESSURE, contact->z);
  413. }
  414. input_mt_sync_frame(input);
  415. input_mt_report_finger_count(input, report_data.contact_cnt);
  416. input_report_key(input, BTN_LEFT, report_data.left);
  417. input_report_key(input, BTN_RIGHT, report_data.right);
  418. input_report_key(input, BTN_MIDDLE, report_data.middle);
  419. input_sync(input);
  420. }
  421. static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
  422. {
  423. int contact_cnt;
  424. int index = psmouse->pktcnt - 1;
  425. u8 *packet = psmouse->packet;
  426. struct cytp_data *cytp = psmouse->private;
  427. if (index < 0 || index > cytp->pkt_size)
  428. return PSMOUSE_BAD_DATA;
  429. if (index == 0 && (packet[0] & 0xfc) == 0) {
  430. /* call packet process for reporting finger leave. */
  431. cypress_process_packet(psmouse, 1);
  432. return PSMOUSE_FULL_PACKET;
  433. }
  434. /*
  435. * Perform validation (and adjust packet size) based only on the
  436. * first byte; allow all further bytes through.
  437. */
  438. if (index != 0)
  439. return PSMOUSE_GOOD_DATA;
  440. /*
  441. * If absolute/relative mode bit has not been set yet, just pass
  442. * the byte through.
  443. */
  444. if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0)
  445. return PSMOUSE_GOOD_DATA;
  446. if ((packet[0] & 0x08) == 0x08)
  447. return PSMOUSE_BAD_DATA;
  448. contact_cnt = cypress_get_finger_count(packet[0]);
  449. if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
  450. cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
  451. else
  452. cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5);
  453. return PSMOUSE_GOOD_DATA;
  454. }
  455. static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
  456. {
  457. struct cytp_data *cytp = psmouse->private;
  458. if (psmouse->pktcnt >= cytp->pkt_size) {
  459. cypress_process_packet(psmouse, 0);
  460. return PSMOUSE_FULL_PACKET;
  461. }
  462. return cypress_validate_byte(psmouse);
  463. }
  464. static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
  465. {
  466. struct cytp_data *cytp = psmouse->private;
  467. u8 rate_param;
  468. if (rate >= 80) {
  469. psmouse->rate = 80;
  470. cytp->mode |= CYTP_BIT_HIGH_RATE;
  471. } else {
  472. psmouse->rate = 40;
  473. cytp->mode &= ~CYTP_BIT_HIGH_RATE;
  474. }
  475. rate_param = (u8)rate;
  476. ps2_command(&psmouse->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE);
  477. }
  478. static void cypress_disconnect(struct psmouse *psmouse)
  479. {
  480. cypress_reset(psmouse);
  481. kfree(psmouse->private);
  482. psmouse->private = NULL;
  483. }
  484. static int cypress_reconnect(struct psmouse *psmouse)
  485. {
  486. int tries = CYTP_PS2_CMD_TRIES;
  487. int error;
  488. do {
  489. cypress_reset(psmouse);
  490. error = cypress_detect(psmouse, false);
  491. } while (error && (--tries > 0));
  492. if (error) {
  493. psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
  494. return error;
  495. }
  496. error = cypress_set_absolute_mode(psmouse);
  497. if (error) {
  498. psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
  499. return error;
  500. }
  501. return 0;
  502. }
  503. int cypress_init(struct psmouse *psmouse)
  504. {
  505. struct cytp_data *cytp;
  506. int error;
  507. cytp = kzalloc_obj(*cytp);
  508. if (!cytp)
  509. return -ENOMEM;
  510. psmouse->private = cytp;
  511. psmouse->pktsize = 8;
  512. cypress_reset(psmouse);
  513. error = cypress_query_hardware(psmouse);
  514. if (error) {
  515. psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
  516. goto err_exit;
  517. }
  518. error = cypress_set_absolute_mode(psmouse);
  519. if (error) {
  520. psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
  521. goto err_exit;
  522. }
  523. error = cypress_set_input_params(psmouse->dev, cytp);
  524. if (error) {
  525. psmouse_err(psmouse, "init: Unable to set input params.\n");
  526. goto err_exit;
  527. }
  528. psmouse->model = 1;
  529. psmouse->protocol_handler = cypress_protocol_handler;
  530. psmouse->set_rate = cypress_set_rate;
  531. psmouse->disconnect = cypress_disconnect;
  532. psmouse->reconnect = cypress_reconnect;
  533. psmouse->cleanup = cypress_reset;
  534. psmouse->resync_time = 0;
  535. return 0;
  536. err_exit:
  537. /*
  538. * Reset Cypress Trackpad as a standard mouse. Then
  539. * let psmouse driver communicating with it as default PS2 mouse.
  540. */
  541. cypress_reset(psmouse);
  542. psmouse->private = NULL;
  543. kfree(cytp);
  544. return error;
  545. }