Lines Matching +full:left +full:- +full:input +full:- +full:single +full:- +full:end

1 // SPDX-License-Identifier: GPL-2.0-only
3 * OLPC HGPK (XO-1) touchpad PS/2 mouse driver
5 * Copyright (c) 2006-2008 One Laptop Per Child
13 * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
31 #include <linux/input.h>
126 struct hgpk_data *priv = psmouse->private; in hgpk_discard_decay_hack()
135 (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) { in hgpk_discard_decay_hack()
137 priv->xbigj = avx; in hgpk_discard_decay_hack()
138 } else if (approx_half(avx, priv->xbigj)) { in hgpk_discard_decay_hack()
140 priv->xbigj = avx; in hgpk_discard_decay_hack()
141 priv->xsaw_secondary++; in hgpk_discard_decay_hack()
143 if (priv->xbigj && priv->xsaw_secondary > 1) in hgpk_discard_decay_hack()
145 priv->xbigj = 0; in hgpk_discard_decay_hack()
146 priv->xsaw_secondary = 0; in hgpk_discard_decay_hack()
150 (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) { in hgpk_discard_decay_hack()
152 priv->ybigj = avy; in hgpk_discard_decay_hack()
153 } else if (approx_half(avy, priv->ybigj)) { in hgpk_discard_decay_hack()
155 priv->ybigj = avy; in hgpk_discard_decay_hack()
156 priv->ysaw_secondary++; in hgpk_discard_decay_hack()
158 if (priv->ybigj && priv->ysaw_secondary > 1) in hgpk_discard_decay_hack()
160 priv->ybigj = 0; in hgpk_discard_decay_hack()
161 priv->ysaw_secondary = 0; in hgpk_discard_decay_hack()
164 priv->xlast = avx; in hgpk_discard_decay_hack()
165 priv->ylast = avy; in hgpk_discard_decay_hack()
169 psmouse_queue_work(psmouse, &priv->recalib_wq, in hgpk_discard_decay_hack()
173 return priv->xbigj || priv->ybigj; in hgpk_discard_decay_hack()
178 priv->spew_count = 0; in hgpk_reset_spew_detection()
179 priv->dupe_count = 0; in hgpk_reset_spew_detection()
180 priv->x_tally = 0; in hgpk_reset_spew_detection()
181 priv->y_tally = 0; in hgpk_reset_spew_detection()
182 priv->spew_flag = NO_SPEW; in hgpk_reset_spew_detection()
187 struct hgpk_data *priv = psmouse->private; in hgpk_reset_hack_state()
189 priv->abs_x = priv->abs_y = -1; in hgpk_reset_hack_state()
190 priv->xlast = priv->ylast = ILLEGAL_XY; in hgpk_reset_hack_state()
191 priv->xbigj = priv->ybigj = 0; in hgpk_reset_hack_state()
192 priv->xsaw_secondary = priv->ysaw_secondary = 0; in hgpk_reset_hack_state()
203 * The packets that are spewed tend to all have deltas between -2 and 2, and
205 * tend to end up in the same location; if we tally up the changes over
206 * 100 packets, we end up w/ a final delta of close to 0. This happens
214 struct hgpk_data *priv = psmouse->private; in hgpk_spewing_hack()
217 * a false-positive! */ in hgpk_spewing_hack()
233 priv->x_tally += x; in hgpk_spewing_hack()
234 priv->y_tally += y; in hgpk_spewing_hack()
236 switch (priv->spew_flag) { in hgpk_spewing_hack()
239 priv->spew_flag = MAYBE_SPEWING; in hgpk_spewing_hack()
244 priv->spew_count++; in hgpk_spewing_hack()
246 if (priv->spew_count < SPEW_WATCH_COUNT) in hgpk_spewing_hack()
250 priv->spew_flag = SPEW_DETECTED; in hgpk_spewing_hack()
259 if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) { in hgpk_spewing_hack()
261 priv->x_tally, priv->y_tally); in hgpk_spewing_hack()
262 priv->spew_flag = RECALIBRATING; in hgpk_spewing_hack()
263 psmouse_queue_work(psmouse, &priv->recalib_wq, in hgpk_spewing_hack()
278 * byte 0: y-over x-over y-neg x-neg 1 0 swr swl
282 * swr/swl are the left/right buttons.
283 * x-neg/y-neg are the x and y delta negative bits
284 * x-over/y-over are the x and y overflow bits
286 * ---
288 * HGPK Advanced Mode - single-mode format
293 * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0
294 * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw
301 * swr/swl are the left/right buttons.
303 * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a
308 struct hgpk_data *priv = psmouse->private; in hgpk_is_byte_valid()
309 int pktcnt = psmouse->pktcnt; in hgpk_is_byte_valid()
312 switch (priv->mode) { in hgpk_is_byte_valid()
319 packet[0] == HGPK_GS : !(packet[pktcnt - 1] & 0x80); in hgpk_is_byte_valid()
324 packet[0] == HGPK_PT : !(packet[pktcnt - 1] & 0x80); in hgpk_is_byte_valid()
335 priv->mode, pktcnt, 6, psmouse->packet); in hgpk_is_byte_valid()
342 struct hgpk_data *priv = psmouse->private; in hgpk_process_advanced_packet()
343 struct input_dev *idev = psmouse->dev; in hgpk_process_advanced_packet()
344 unsigned char *packet = psmouse->packet; in hgpk_process_advanced_packet()
346 int left = !!(packet[3] & 1); in hgpk_process_advanced_packet() local
351 if (priv->mode == HGPK_MODE_GLIDESENSOR) { in hgpk_process_advanced_packet()
371 left, right, x, y); in hgpk_process_advanced_packet()
374 input_report_key(idev, BTN_LEFT, left); in hgpk_process_advanced_packet()
390 if (x == priv->abs_x && y == priv->abs_y) { in hgpk_process_advanced_packet()
391 if (++priv->dupe_count > SPEW_WATCH_COUNT) { in hgpk_process_advanced_packet()
394 priv->spew_flag = RECALIBRATING; in hgpk_process_advanced_packet()
395 psmouse_queue_work(psmouse, &priv->recalib_wq, in hgpk_process_advanced_packet()
402 priv->dupe_count = 0; in hgpk_process_advanced_packet()
405 if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) { in hgpk_process_advanced_packet()
406 int x_diff = priv->abs_x - x; in hgpk_process_advanced_packet()
407 int y_diff = priv->abs_y - y; in hgpk_process_advanced_packet()
413 hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff); in hgpk_process_advanced_packet()
418 priv->abs_x = x; in hgpk_process_advanced_packet()
419 priv->abs_y = y; in hgpk_process_advanced_packet()
427 struct input_dev *dev = psmouse->dev; in hgpk_process_simple_packet()
428 unsigned char *packet = psmouse->packet; in hgpk_process_simple_packet()
429 int left = packet[0] & 1; in hgpk_process_simple_packet() local
431 int x = packet[1] - ((packet[0] << 4) & 0x100); in hgpk_process_simple_packet()
432 int y = ((packet[0] << 3) & 0x100) - packet[2]; in hgpk_process_simple_packet()
436 "overflow -- 0x%02x 0x%02x 0x%02x\n", in hgpk_process_simple_packet()
445 hgpk_spewing_hack(psmouse, left, right, x, y); in hgpk_process_simple_packet()
449 left, right, x, y); in hgpk_process_simple_packet()
451 input_report_key(dev, BTN_LEFT, left); in hgpk_process_simple_packet()
462 struct hgpk_data *priv = psmouse->private; in hgpk_process_byte()
464 if (!hgpk_is_byte_valid(psmouse, psmouse->packet)) in hgpk_process_byte()
467 if (psmouse->pktcnt >= psmouse->pktsize) { in hgpk_process_byte()
468 if (priv->mode == HGPK_MODE_MOUSE) in hgpk_process_byte()
475 if (priv->recalib_window) { in hgpk_process_byte()
476 if (time_before(jiffies, priv->recalib_window)) { in hgpk_process_byte()
483 psmouse_queue_work(psmouse, &priv->recalib_wq, in hgpk_process_byte()
486 priv->recalib_window = 0; in hgpk_process_byte()
494 struct ps2dev *ps2dev = &psmouse->ps2dev; in hgpk_select_mode()
495 struct hgpk_data *priv = psmouse->private; in hgpk_select_mode()
509 switch (priv->mode) { in hgpk_select_mode()
511 psmouse->pktsize = 3; in hgpk_select_mode()
516 psmouse->pktsize = 6; in hgpk_select_mode()
521 return -EIO; in hgpk_select_mode()
524 cmd = priv->mode == HGPK_MODE_GLIDESENSOR ? in hgpk_select_mode()
528 return -EIO; in hgpk_select_mode()
532 return -EINVAL; in hgpk_select_mode()
538 static void hgpk_setup_input_device(struct input_dev *input, in hgpk_setup_input_device() argument
543 input->name = old_input->name; in hgpk_setup_input_device()
544 input->phys = old_input->phys; in hgpk_setup_input_device()
545 input->id = old_input->id; in hgpk_setup_input_device()
546 input->dev.parent = old_input->dev.parent; in hgpk_setup_input_device()
549 memset(input->evbit, 0, sizeof(input->evbit)); in hgpk_setup_input_device()
550 memset(input->relbit, 0, sizeof(input->relbit)); in hgpk_setup_input_device()
551 memset(input->keybit, 0, sizeof(input->keybit)); in hgpk_setup_input_device()
553 /* All modes report left and right buttons */ in hgpk_setup_input_device()
554 __set_bit(EV_KEY, input->evbit); in hgpk_setup_input_device()
555 __set_bit(BTN_LEFT, input->keybit); in hgpk_setup_input_device()
556 __set_bit(BTN_RIGHT, input->keybit); in hgpk_setup_input_device()
560 __set_bit(EV_REL, input->evbit); in hgpk_setup_input_device()
561 __set_bit(REL_X, input->relbit); in hgpk_setup_input_device()
562 __set_bit(REL_Y, input->relbit); in hgpk_setup_input_device()
566 __set_bit(BTN_TOUCH, input->keybit); in hgpk_setup_input_device()
567 __set_bit(BTN_TOOL_FINGER, input->keybit); in hgpk_setup_input_device()
569 __set_bit(EV_ABS, input->evbit); in hgpk_setup_input_device()
572 input_set_abs_params(input, ABS_PRESSURE, 0, 15, 0, 0); in hgpk_setup_input_device()
575 input_set_abs_params(input, ABS_X, 0, 399, 0, 0); in hgpk_setup_input_device()
576 input_set_abs_params(input, ABS_Y, 0, 290, 0, 0); in hgpk_setup_input_device()
579 input_abs_set_res(input, ABS_X, 8); in hgpk_setup_input_device()
580 input_abs_set_res(input, ABS_Y, 8); in hgpk_setup_input_device()
584 __set_bit(BTN_TOUCH, input->keybit); in hgpk_setup_input_device()
585 __set_bit(BTN_TOOL_FINGER, input->keybit); in hgpk_setup_input_device()
587 __set_bit(EV_ABS, input->evbit); in hgpk_setup_input_device()
590 input_set_abs_params(input, ABS_X, 0, 999, 0, 0); in hgpk_setup_input_device()
591 input_set_abs_params(input, ABS_Y, 5, 239, 0, 0); in hgpk_setup_input_device()
594 input_abs_set_res(input, ABS_X, 6); in hgpk_setup_input_device()
595 input_abs_set_res(input, ABS_Y, 8); in hgpk_setup_input_device()
610 struct ps2dev *ps2dev = &psmouse->ps2dev; in hgpk_reset_device()
617 return -1; in hgpk_reset_device()
637 struct hgpk_data *priv = psmouse->private; in hgpk_force_recalibrate()
640 /* C-series touchpads added the recalibrate command */ in hgpk_force_recalibrate()
641 if (psmouse->model < HGPK_MODEL_C) in hgpk_force_recalibrate()
666 return -1; in hgpk_force_recalibrate()
677 priv->recalib_window = jiffies + in hgpk_force_recalibrate()
686 * we drive MS-DAT low. Measuring with a 1mA resolution ammeter says that
689 * We have no formal spec that details this operation -- the low-power
690 * sequence came from a long-lost email trail.
694 struct ps2dev *ps2dev = &psmouse->ps2dev; in hgpk_toggle_powersave()
698 /* Added on D-series touchpads */ in hgpk_toggle_powersave()
699 if (psmouse->model < HGPK_MODEL_D) in hgpk_toggle_powersave()
706 * Sending a byte will drive MS-DAT low; this will wake up in hgpk_toggle_powersave()
708 * means we can continue with the touchpad re-init. ALPS in hgpk_toggle_powersave()
712 for (timeo = 20; timeo > 0; timeo--) { in hgpk_toggle_powersave()
733 return -1; in hgpk_toggle_powersave()
748 return -1; in hgpk_poll()
753 struct hgpk_data *priv = psmouse->private; in hgpk_reconnect()
761 if (psmouse->ps2dev.serio->dev.power.power_state.event != in hgpk_reconnect()
765 priv->powered = 1; in hgpk_reconnect()
771 struct hgpk_data *priv = psmouse->private; in hgpk_show_powered()
773 return sprintf(buf, "%d\n", priv->powered); in hgpk_show_powered()
779 struct hgpk_data *priv = psmouse->private; in hgpk_set_powered()
788 return -EINVAL; in hgpk_set_powered()
790 if (value != priv->powered) { in hgpk_set_powered()
797 priv->powered = value; in hgpk_set_powered()
808 struct hgpk_data *priv = psmouse->private; in attr_show_mode()
810 return sprintf(buf, "%s\n", hgpk_mode_names[priv->mode]); in attr_show_mode()
816 struct hgpk_data *priv = psmouse->private; in attr_set_mode()
817 enum hgpk_mode old_mode = priv->mode; in attr_set_mode()
819 struct input_dev *old_dev = psmouse->dev; in attr_set_mode()
824 return -EINVAL; in attr_set_mode()
831 return -ENOMEM; in attr_set_mode()
836 priv->mode = new_mode; in attr_set_mode()
849 psmouse->dev = new_dev; in attr_set_mode()
856 priv->mode = old_mode; in attr_set_mode()
868 return -EINVAL; in hgpk_trigger_recal_show()
874 struct hgpk_data *priv = psmouse->private; in hgpk_trigger_recal()
883 return -EINVAL; in hgpk_trigger_recal()
890 psmouse_queue_work(psmouse, &priv->recalib_wq, 0); in hgpk_trigger_recal()
899 struct hgpk_data *priv = psmouse->private; in hgpk_disconnect()
901 device_remove_file(&psmouse->ps2dev.serio->dev, in hgpk_disconnect()
903 device_remove_file(&psmouse->ps2dev.serio->dev, in hgpk_disconnect()
906 if (psmouse->model >= HGPK_MODEL_C) in hgpk_disconnect()
907 device_remove_file(&psmouse->ps2dev.serio->dev, in hgpk_disconnect()
918 struct psmouse *psmouse = priv->psmouse; in hgpk_recalib_work()
926 struct hgpk_data *priv = psmouse->private; in hgpk_register()
930 psmouse->protocol_handler = hgpk_process_byte; in hgpk_register()
931 psmouse->poll = hgpk_poll; in hgpk_register()
932 psmouse->disconnect = hgpk_disconnect; in hgpk_register()
933 psmouse->reconnect = hgpk_reconnect; in hgpk_register()
936 psmouse->resync_time = 0; in hgpk_register()
938 psmouse->resetafter = 1024; in hgpk_register()
940 hgpk_setup_input_device(psmouse->dev, NULL, priv->mode); in hgpk_register()
942 err = device_create_file(&psmouse->ps2dev.serio->dev, in hgpk_register()
949 err = device_create_file(&psmouse->ps2dev.serio->dev, in hgpk_register()
957 /* C-series touchpads added the recalibrate command */ in hgpk_register()
958 if (psmouse->model >= HGPK_MODEL_C) { in hgpk_register()
959 err = device_create_file(&psmouse->ps2dev.serio->dev, in hgpk_register()
971 device_remove_file(&psmouse->ps2dev.serio->dev, in hgpk_register()
974 device_remove_file(&psmouse->ps2dev.serio->dev, in hgpk_register()
986 err = -ENOMEM; in hgpk_init()
990 psmouse->private = priv; in hgpk_init()
992 priv->psmouse = psmouse; in hgpk_init()
993 priv->powered = true; in hgpk_init()
994 priv->mode = hgpk_default_mode; in hgpk_init()
995 INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); in hgpk_init()
1015 struct ps2dev *ps2dev = &psmouse->ps2dev; in hgpk_get_model()
1023 return -EIO; in hgpk_get_model()
1030 return -ENODEV; in hgpk_get_model()
1046 psmouse->vendor = "ALPS"; in hgpk_detect()
1047 psmouse->name = "HGPK"; in hgpk_detect()
1048 psmouse->model = version; in hgpk_detect()