0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/slab.h>
0018 #include <linux/serio.h>
0019 #include <linux/libps2.h>
0020 #include <linux/input.h>
0021 #include <linux/input/mt.h>
0022 #include <linux/sched.h>
0023 #include <linux/wait.h>
0024
0025 #include "cypress_ps2.h"
0026
0027 #undef CYTP_DEBUG_VERBOSE
0028
0029 static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
0030 {
0031 struct cytp_data *cytp = psmouse->private;
0032 cytp->pkt_size = n;
0033 }
0034
0035 static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200};
0036 static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
0037
0038 static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
0039 {
0040 struct ps2dev *ps2dev = &psmouse->ps2dev;
0041
0042 if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
0043 psmouse_dbg(psmouse,
0044 "sending command 0x%02x failed, resp 0x%02x\n",
0045 value & 0xff, ps2dev->nak);
0046 if (ps2dev->nak == CYTP_PS2_RETRY)
0047 return CYTP_PS2_RETRY;
0048 else
0049 return CYTP_PS2_ERROR;
0050 }
0051
0052 #ifdef CYTP_DEBUG_VERBOSE
0053 psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
0054 value & 0xff);
0055 #endif
0056
0057 return 0;
0058 }
0059
0060 static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
0061 unsigned char data)
0062 {
0063 struct ps2dev *ps2dev = &psmouse->ps2dev;
0064 int tries = CYTP_PS2_CMD_TRIES;
0065 int rc;
0066
0067 ps2_begin_command(ps2dev);
0068
0069 do {
0070
0071
0072
0073
0074
0075 rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff);
0076 if (rc == CYTP_PS2_RETRY) {
0077 rc = cypress_ps2_sendbyte(psmouse, 0x00);
0078 if (rc == CYTP_PS2_RETRY)
0079 rc = cypress_ps2_sendbyte(psmouse, 0x0a);
0080 }
0081 if (rc == CYTP_PS2_ERROR)
0082 continue;
0083
0084 rc = cypress_ps2_sendbyte(psmouse, data);
0085 if (rc == CYTP_PS2_RETRY)
0086 rc = cypress_ps2_sendbyte(psmouse, data);
0087 if (rc == CYTP_PS2_ERROR)
0088 continue;
0089 else
0090 break;
0091 } while (--tries > 0);
0092
0093 ps2_end_command(ps2dev);
0094
0095 return rc;
0096 }
0097
0098 static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
0099 unsigned char cmd,
0100 unsigned char *param)
0101 {
0102 int rc;
0103 struct ps2dev *ps2dev = &psmouse->ps2dev;
0104 enum psmouse_state old_state;
0105 int pktsize;
0106
0107 ps2_begin_command(ps2dev);
0108
0109 old_state = psmouse->state;
0110 psmouse->state = PSMOUSE_CMD_MODE;
0111 psmouse->pktcnt = 0;
0112
0113 pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
0114 memset(param, 0, pktsize);
0115
0116 rc = cypress_ps2_sendbyte(psmouse, 0xe9);
0117 if (rc < 0)
0118 goto out;
0119
0120 wait_event_timeout(ps2dev->wait,
0121 (psmouse->pktcnt >= pktsize),
0122 msecs_to_jiffies(CYTP_CMD_TIMEOUT));
0123
0124 memcpy(param, psmouse->packet, pktsize);
0125
0126 psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
0127 cmd, pktsize, param);
0128
0129 out:
0130 psmouse->state = old_state;
0131 psmouse->pktcnt = 0;
0132
0133 ps2_end_command(ps2dev);
0134
0135 return rc;
0136 }
0137
0138 static bool cypress_verify_cmd_state(struct psmouse *psmouse,
0139 unsigned char cmd, unsigned char *param)
0140 {
0141 bool rate_match = false;
0142 bool resolution_match = false;
0143 int i;
0144
0145
0146 if (cmd == CYTP_CMD_READ_CYPRESS_ID ||
0147 cmd == CYTP_CMD_STANDARD_MODE ||
0148 cmd == CYTP_CMD_READ_TP_METRICS)
0149 return true;
0150
0151 if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID &&
0152 (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) {
0153 for (i = 0; i < sizeof(cytp_resolution); i++)
0154 if (cytp_resolution[i] == param[1])
0155 resolution_match = true;
0156
0157 for (i = 0; i < sizeof(cytp_rate); i++)
0158 if (cytp_rate[i] == param[2])
0159 rate_match = true;
0160
0161 if (resolution_match && rate_match)
0162 return true;
0163 }
0164
0165 psmouse_dbg(psmouse, "verify cmd state failed.\n");
0166 return false;
0167 }
0168
0169 static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
0170 unsigned char *param)
0171 {
0172 int tries = CYTP_PS2_CMD_TRIES;
0173 int rc;
0174
0175 psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n",
0176 cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd),
0177 DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd));
0178
0179 do {
0180 cypress_ps2_ext_cmd(psmouse,
0181 PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd));
0182 cypress_ps2_ext_cmd(psmouse,
0183 PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd));
0184 cypress_ps2_ext_cmd(psmouse,
0185 PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd));
0186 cypress_ps2_ext_cmd(psmouse,
0187 PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd));
0188
0189 rc = cypress_ps2_read_cmd_status(psmouse, cmd, param);
0190 if (rc)
0191 continue;
0192
0193 if (cypress_verify_cmd_state(psmouse, cmd, param))
0194 return 0;
0195
0196 } while (--tries > 0);
0197
0198 return -EIO;
0199 }
0200
0201 int cypress_detect(struct psmouse *psmouse, bool set_properties)
0202 {
0203 unsigned char param[3];
0204
0205 if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
0206 return -ENODEV;
0207
0208
0209 if (param[0] != 0x33 || param[1] != 0xCC)
0210 return -ENODEV;
0211
0212 if (set_properties) {
0213 psmouse->vendor = "Cypress";
0214 psmouse->name = "Trackpad";
0215 }
0216
0217 return 0;
0218 }
0219
0220 static int cypress_read_fw_version(struct psmouse *psmouse)
0221 {
0222 struct cytp_data *cytp = psmouse->private;
0223 unsigned char param[3];
0224
0225 if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
0226 return -ENODEV;
0227
0228
0229 if (param[0] != 0x33 || param[1] != 0xCC)
0230 return -ENODEV;
0231
0232 cytp->fw_version = param[2] & FW_VERSION_MASX;
0233 cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0;
0234
0235
0236
0237
0238
0239 if (cytp->fw_version >= 11)
0240 cytp->tp_metrics_supported = 0;
0241
0242 psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version);
0243 psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n",
0244 cytp->tp_metrics_supported);
0245
0246 return 0;
0247 }
0248
0249 static int cypress_read_tp_metrics(struct psmouse *psmouse)
0250 {
0251 struct cytp_data *cytp = psmouse->private;
0252 unsigned char param[8];
0253
0254
0255 cytp->tp_width = CYTP_DEFAULT_WIDTH;
0256 cytp->tp_high = CYTP_DEFAULT_HIGH;
0257 cytp->tp_max_abs_x = CYTP_ABS_MAX_X;
0258 cytp->tp_max_abs_y = CYTP_ABS_MAX_Y;
0259 cytp->tp_min_pressure = CYTP_MIN_PRESSURE;
0260 cytp->tp_max_pressure = CYTP_MAX_PRESSURE;
0261 cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
0262 cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
0263
0264 if (!cytp->tp_metrics_supported)
0265 return 0;
0266
0267 memset(param, 0, sizeof(param));
0268 if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) {
0269
0270 cytp->tp_max_abs_x = (param[1] << 8) | param[0];
0271 cytp->tp_max_abs_y = (param[3] << 8) | param[2];
0272 cytp->tp_min_pressure = param[4];
0273 cytp->tp_max_pressure = param[5];
0274 }
0275
0276 if (!cytp->tp_max_pressure ||
0277 cytp->tp_max_pressure < cytp->tp_min_pressure ||
0278 !cytp->tp_width || !cytp->tp_high ||
0279 !cytp->tp_max_abs_x ||
0280 cytp->tp_max_abs_x < cytp->tp_width ||
0281 !cytp->tp_max_abs_y ||
0282 cytp->tp_max_abs_y < cytp->tp_high)
0283 return -EINVAL;
0284
0285 cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
0286 cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
0287
0288 #ifdef CYTP_DEBUG_VERBOSE
0289 psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n");
0290 psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width);
0291 psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high);
0292 psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x);
0293 psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y);
0294 psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure);
0295 psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure);
0296 psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x);
0297 psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y);
0298
0299 psmouse_dbg(psmouse, "tp_type_APA = %d\n",
0300 (param[6] & TP_METRICS_BIT_APA) ? 1 : 0);
0301 psmouse_dbg(psmouse, "tp_type_MTG = %d\n",
0302 (param[6] & TP_METRICS_BIT_MTG) ? 1 : 0);
0303 psmouse_dbg(psmouse, "tp_palm = %d\n",
0304 (param[6] & TP_METRICS_BIT_PALM) ? 1 : 0);
0305 psmouse_dbg(psmouse, "tp_stubborn = %d\n",
0306 (param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0);
0307 psmouse_dbg(psmouse, "tp_1f_jitter = %d\n",
0308 (param[6] & TP_METRICS_BIT_1F_JITTER) >> 2);
0309 psmouse_dbg(psmouse, "tp_2f_jitter = %d\n",
0310 (param[6] & TP_METRICS_BIT_2F_JITTER) >> 4);
0311 psmouse_dbg(psmouse, "tp_1f_spike = %d\n",
0312 param[7] & TP_METRICS_BIT_1F_SPIKE);
0313 psmouse_dbg(psmouse, "tp_2f_spike = %d\n",
0314 (param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2);
0315 psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n",
0316 (param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4);
0317 #endif
0318
0319 return 0;
0320 }
0321
0322 static int cypress_query_hardware(struct psmouse *psmouse)
0323 {
0324 int ret;
0325
0326 ret = cypress_read_fw_version(psmouse);
0327 if (ret)
0328 return ret;
0329
0330 ret = cypress_read_tp_metrics(psmouse);
0331 if (ret)
0332 return ret;
0333
0334 return 0;
0335 }
0336
0337 static int cypress_set_absolute_mode(struct psmouse *psmouse)
0338 {
0339 struct cytp_data *cytp = psmouse->private;
0340 unsigned char param[3];
0341
0342 if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0)
0343 return -1;
0344
0345 cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
0346 | CYTP_BIT_ABS_PRESSURE;
0347 cypress_set_packet_size(psmouse, 5);
0348
0349 return 0;
0350 }
0351
0352
0353
0354
0355
0356 static void cypress_reset(struct psmouse *psmouse)
0357 {
0358 struct cytp_data *cytp = psmouse->private;
0359
0360 cytp->mode = 0;
0361
0362 psmouse_reset(psmouse);
0363 }
0364
0365 static int cypress_set_input_params(struct input_dev *input,
0366 struct cytp_data *cytp)
0367 {
0368 int ret;
0369
0370 if (!cytp->tp_res_x || !cytp->tp_res_y)
0371 return -EINVAL;
0372
0373 __set_bit(EV_ABS, input->evbit);
0374 input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0);
0375 input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0);
0376 input_set_abs_params(input, ABS_PRESSURE,
0377 cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0);
0378 input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
0379
0380
0381 input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0);
0382 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
0383 input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
0384
0385 ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
0386 INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);
0387 if (ret < 0)
0388 return ret;
0389
0390 __set_bit(INPUT_PROP_SEMI_MT, input->propbit);
0391
0392 input_abs_set_res(input, ABS_X, cytp->tp_res_x);
0393 input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
0394
0395 input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x);
0396 input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y);
0397
0398 __set_bit(BTN_TOUCH, input->keybit);
0399 __set_bit(BTN_TOOL_FINGER, input->keybit);
0400 __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
0401 __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
0402 __set_bit(BTN_TOOL_QUADTAP, input->keybit);
0403 __set_bit(BTN_TOOL_QUINTTAP, input->keybit);
0404
0405 __clear_bit(EV_REL, input->evbit);
0406 __clear_bit(REL_X, input->relbit);
0407 __clear_bit(REL_Y, input->relbit);
0408
0409 __set_bit(EV_KEY, input->evbit);
0410 __set_bit(BTN_LEFT, input->keybit);
0411 __set_bit(BTN_RIGHT, input->keybit);
0412 __set_bit(BTN_MIDDLE, input->keybit);
0413
0414 return 0;
0415 }
0416
0417 static int cypress_get_finger_count(unsigned char header_byte)
0418 {
0419 unsigned char bits6_7;
0420 int finger_count;
0421
0422 bits6_7 = header_byte >> 6;
0423 finger_count = bits6_7 & 0x03;
0424
0425 if (finger_count == 1)
0426 return 1;
0427
0428 if (header_byte & ABS_HSCROLL_BIT) {
0429
0430 switch (finger_count) {
0431 case 0: return 4;
0432 case 2: return 5;
0433 default:
0434
0435 return 0;
0436 }
0437 }
0438
0439 return finger_count;
0440 }
0441
0442
0443 static int cypress_parse_packet(struct psmouse *psmouse,
0444 struct cytp_data *cytp, struct cytp_report_data *report_data)
0445 {
0446 unsigned char *packet = psmouse->packet;
0447 unsigned char header_byte = packet[0];
0448
0449 memset(report_data, 0, sizeof(struct cytp_report_data));
0450
0451 report_data->contact_cnt = cypress_get_finger_count(header_byte);
0452 report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
0453
0454 if (report_data->contact_cnt == 1) {
0455 report_data->contacts[0].x =
0456 ((packet[1] & 0x70) << 4) | packet[2];
0457 report_data->contacts[0].y =
0458 ((packet[1] & 0x07) << 8) | packet[3];
0459 if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
0460 report_data->contacts[0].z = packet[4];
0461
0462 } else if (report_data->contact_cnt >= 2) {
0463 report_data->contacts[0].x =
0464 ((packet[1] & 0x70) << 4) | packet[2];
0465 report_data->contacts[0].y =
0466 ((packet[1] & 0x07) << 8) | packet[3];
0467 if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
0468 report_data->contacts[0].z = packet[4];
0469
0470 report_data->contacts[1].x =
0471 ((packet[5] & 0xf0) << 4) | packet[6];
0472 report_data->contacts[1].y =
0473 ((packet[5] & 0x0f) << 8) | packet[7];
0474 if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
0475 report_data->contacts[1].z = report_data->contacts[0].z;
0476 }
0477
0478 report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
0479 report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0;
0480
0481
0482
0483
0484
0485
0486
0487 if (report_data->tap)
0488 report_data->left = 0;
0489
0490 #ifdef CYTP_DEBUG_VERBOSE
0491 {
0492 int i;
0493 int n = report_data->contact_cnt;
0494 psmouse_dbg(psmouse, "Dump parsed report data as below:\n");
0495 psmouse_dbg(psmouse, "contact_cnt = %d\n",
0496 report_data->contact_cnt);
0497 if (n > CYTP_MAX_MT_SLOTS)
0498 n = CYTP_MAX_MT_SLOTS;
0499 for (i = 0; i < n; i++)
0500 psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i,
0501 report_data->contacts[i].x,
0502 report_data->contacts[i].y,
0503 report_data->contacts[i].z);
0504 psmouse_dbg(psmouse, "left = %d\n", report_data->left);
0505 psmouse_dbg(psmouse, "right = %d\n", report_data->right);
0506 psmouse_dbg(psmouse, "middle = %d\n", report_data->middle);
0507 }
0508 #endif
0509
0510 return 0;
0511 }
0512
0513 static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
0514 {
0515 int i;
0516 struct input_dev *input = psmouse->dev;
0517 struct cytp_data *cytp = psmouse->private;
0518 struct cytp_report_data report_data;
0519 struct cytp_contact *contact;
0520 struct input_mt_pos pos[CYTP_MAX_MT_SLOTS];
0521 int slots[CYTP_MAX_MT_SLOTS];
0522 int n;
0523
0524 cypress_parse_packet(psmouse, cytp, &report_data);
0525
0526 n = report_data.contact_cnt;
0527 if (n > CYTP_MAX_MT_SLOTS)
0528 n = CYTP_MAX_MT_SLOTS;
0529
0530 for (i = 0; i < n; i++) {
0531 contact = &report_data.contacts[i];
0532 pos[i].x = contact->x;
0533 pos[i].y = contact->y;
0534 }
0535
0536 input_mt_assign_slots(input, slots, pos, n, 0);
0537
0538 for (i = 0; i < n; i++) {
0539 contact = &report_data.contacts[i];
0540 input_mt_slot(input, slots[i]);
0541 input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
0542 input_report_abs(input, ABS_MT_POSITION_X, contact->x);
0543 input_report_abs(input, ABS_MT_POSITION_Y, contact->y);
0544 input_report_abs(input, ABS_MT_PRESSURE, contact->z);
0545 }
0546
0547 input_mt_sync_frame(input);
0548
0549 input_mt_report_finger_count(input, report_data.contact_cnt);
0550
0551 input_report_key(input, BTN_LEFT, report_data.left);
0552 input_report_key(input, BTN_RIGHT, report_data.right);
0553 input_report_key(input, BTN_MIDDLE, report_data.middle);
0554
0555 input_sync(input);
0556 }
0557
0558 static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
0559 {
0560 int contact_cnt;
0561 int index = psmouse->pktcnt - 1;
0562 unsigned char *packet = psmouse->packet;
0563 struct cytp_data *cytp = psmouse->private;
0564
0565 if (index < 0 || index > cytp->pkt_size)
0566 return PSMOUSE_BAD_DATA;
0567
0568 if (index == 0 && (packet[0] & 0xfc) == 0) {
0569
0570 cypress_process_packet(psmouse, 1);
0571 return PSMOUSE_FULL_PACKET;
0572 }
0573
0574
0575
0576
0577
0578 if (index != 0)
0579 return PSMOUSE_GOOD_DATA;
0580
0581
0582
0583
0584
0585 if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0)
0586 return PSMOUSE_GOOD_DATA;
0587
0588 if ((packet[0] & 0x08) == 0x08)
0589 return PSMOUSE_BAD_DATA;
0590
0591 contact_cnt = cypress_get_finger_count(packet[0]);
0592 if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
0593 cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
0594 else
0595 cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5);
0596
0597 return PSMOUSE_GOOD_DATA;
0598 }
0599
0600 static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
0601 {
0602 struct cytp_data *cytp = psmouse->private;
0603
0604 if (psmouse->pktcnt >= cytp->pkt_size) {
0605 cypress_process_packet(psmouse, 0);
0606 return PSMOUSE_FULL_PACKET;
0607 }
0608
0609 return cypress_validate_byte(psmouse);
0610 }
0611
0612 static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
0613 {
0614 struct cytp_data *cytp = psmouse->private;
0615
0616 if (rate >= 80) {
0617 psmouse->rate = 80;
0618 cytp->mode |= CYTP_BIT_HIGH_RATE;
0619 } else {
0620 psmouse->rate = 40;
0621 cytp->mode &= ~CYTP_BIT_HIGH_RATE;
0622 }
0623
0624 ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate,
0625 PSMOUSE_CMD_SETRATE);
0626 }
0627
0628 static void cypress_disconnect(struct psmouse *psmouse)
0629 {
0630 cypress_reset(psmouse);
0631 kfree(psmouse->private);
0632 psmouse->private = NULL;
0633 }
0634
0635 static int cypress_reconnect(struct psmouse *psmouse)
0636 {
0637 int tries = CYTP_PS2_CMD_TRIES;
0638 int rc;
0639
0640 do {
0641 cypress_reset(psmouse);
0642 rc = cypress_detect(psmouse, false);
0643 } while (rc && (--tries > 0));
0644
0645 if (rc) {
0646 psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
0647 return -1;
0648 }
0649
0650 if (cypress_set_absolute_mode(psmouse)) {
0651 psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
0652 return -1;
0653 }
0654
0655 return 0;
0656 }
0657
0658 int cypress_init(struct psmouse *psmouse)
0659 {
0660 struct cytp_data *cytp;
0661
0662 cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
0663 if (!cytp)
0664 return -ENOMEM;
0665
0666 psmouse->private = cytp;
0667 psmouse->pktsize = 8;
0668
0669 cypress_reset(psmouse);
0670
0671 if (cypress_query_hardware(psmouse)) {
0672 psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
0673 goto err_exit;
0674 }
0675
0676 if (cypress_set_absolute_mode(psmouse)) {
0677 psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
0678 goto err_exit;
0679 }
0680
0681 if (cypress_set_input_params(psmouse->dev, cytp) < 0) {
0682 psmouse_err(psmouse, "init: Unable to set input params.\n");
0683 goto err_exit;
0684 }
0685
0686 psmouse->model = 1;
0687 psmouse->protocol_handler = cypress_protocol_handler;
0688 psmouse->set_rate = cypress_set_rate;
0689 psmouse->disconnect = cypress_disconnect;
0690 psmouse->reconnect = cypress_reconnect;
0691 psmouse->cleanup = cypress_reset;
0692 psmouse->resync_time = 0;
0693
0694 return 0;
0695
0696 err_exit:
0697
0698
0699
0700
0701 cypress_reset(psmouse);
0702
0703 psmouse->private = NULL;
0704 kfree(cytp);
0705
0706 return -1;
0707 }