^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Fujitsu B-series Lifebook PS/2 TouchScreen driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * TouchScreen detection, absolute mode setting and packet layout is taken from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Harald Hoyer's description of the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/serio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/libps2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "psmouse.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "lifebook.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct lifebook_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct input_dev *dev2; /* Relative device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) char phys[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static bool lifebook_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static const char *desired_serio_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int lifebook_limit_serio3(const struct dmi_system_id *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) desired_serio_phys = "isa0060/serio3";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static bool lifebook_use_6byte_proto;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) lifebook_use_6byte_proto = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static const struct dmi_system_id lifebook_dmi_table[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* FLORA-ie 55mi */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) DMI_MATCH(DMI_PRODUCT_NAME, "FLORA-ie 55mi"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /* LifeBook B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) DMI_MATCH(DMI_PRODUCT_NAME, "Lifebook B Series"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* LifeBook B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B Series"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* Lifebook B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Lifebook B-2130 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) DMI_MATCH(DMI_BOARD_NAME, "ZEPHYR"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* Lifebook B213x/B2150 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B2131/B2133/B2150"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* Zephyr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) DMI_MATCH(DMI_PRODUCT_NAME, "ZEPHYR"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* Panasonic CF-18 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .callback = lifebook_limit_serio3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* Panasonic CF-28 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .callback = lifebook_set_6byte_proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* Panasonic CF-29 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .callback = lifebook_set_6byte_proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* Panasonic CF-72 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .callback = lifebook_set_6byte_proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* Lifebook B142 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) void __init lifebook_module_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) lifebook_present = dmi_check_system(lifebook_dmi_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct lifebook_data *priv = psmouse->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct input_dev *dev1 = psmouse->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct input_dev *dev2 = priv ? priv->dev2 : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) u8 *packet = psmouse->packet;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) bool relative_packet = packet[0] & 0x08;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (relative_packet || !lifebook_use_6byte_proto) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (psmouse->pktcnt != 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return PSMOUSE_GOOD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) switch (psmouse->pktcnt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return (packet[0] & 0xf8) == 0x00 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return PSMOUSE_GOOD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return (packet[3] & 0xf8) == 0xc0 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return (packet[4] & 0xc0) == (packet[2] & 0xc0) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return PSMOUSE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if ((packet[5] & 0xc0) != (packet[1] & 0xc0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return PSMOUSE_BAD_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) break; /* report data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (relative_packet) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!dev2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) psmouse_warn(psmouse,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) "got relative packet but no relative device set up\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (lifebook_use_6byte_proto) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) input_report_abs(dev1, ABS_X,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) input_report_abs(dev1, ABS_Y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) input_report_abs(dev1, ABS_X,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) (packet[1] | ((packet[0] & 0x30) << 4)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) input_report_abs(dev1, ABS_Y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) input_sync(dev1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (dev2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (relative_packet)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) psmouse_report_standard_motion(dev2, packet);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) psmouse_report_standard_buttons(dev2, packet[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) input_sync(dev2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return PSMOUSE_FULL_PACKET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static int lifebook_absolute_mode(struct psmouse *psmouse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct ps2dev *ps2dev = &psmouse->ps2dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) u8 param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) error = psmouse_reset(psmouse);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * Enable absolute output -- ps2_command fails always but if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * you leave this call out the touchscreen will never send
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * absolute coordinates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) param = lifebook_use_6byte_proto ? 0x08 : 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static void lifebook_relative_mode(struct psmouse *psmouse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) struct ps2dev *ps2dev = &psmouse->ps2dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) u8 param = 0x06;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static const u8 params[] = { 0, 1, 2, 2, 3 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) u8 p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (resolution == 0 || resolution > 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) resolution = 400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) p = params[resolution / 100];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) psmouse->resolution = 50 << p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) static void lifebook_disconnect(struct psmouse *psmouse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct lifebook_data *priv = psmouse->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) psmouse_reset(psmouse);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (priv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) input_unregister_device(priv->dev2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) kfree(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) psmouse->private = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) int lifebook_detect(struct psmouse *psmouse, bool set_properties)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (!lifebook_present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (desired_serio_phys &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (set_properties) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) psmouse->vendor = "Fujitsu";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) psmouse->name = "Lifebook TouchScreen";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int lifebook_create_relative_device(struct psmouse *psmouse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct input_dev *dev2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct lifebook_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) int error = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) dev2 = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (!priv || !dev2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) priv->dev2 = dev2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) snprintf(priv->phys, sizeof(priv->phys),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) "%s/input1", psmouse->ps2dev.serio->phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) dev2->phys = priv->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) dev2->name = "LBPS/2 Fujitsu Lifebook Touchpad";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) dev2->id.bustype = BUS_I8042;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) dev2->id.vendor = 0x0002;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) dev2->id.product = PSMOUSE_LIFEBOOK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) dev2->id.version = 0x0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) dev2->dev.parent = &psmouse->ps2dev.serio->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) input_set_capability(dev2, EV_REL, REL_X);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) input_set_capability(dev2, EV_REL, REL_Y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) input_set_capability(dev2, EV_KEY, BTN_LEFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) input_set_capability(dev2, EV_KEY, BTN_RIGHT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) error = input_register_device(priv->dev2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) psmouse->private = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) input_free_device(dev2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) kfree(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) int lifebook_init(struct psmouse *psmouse)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct input_dev *dev1 = psmouse->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) error = lifebook_absolute_mode(psmouse);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Clear default capabilities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) bitmap_zero(dev1->evbit, EV_CNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) bitmap_zero(dev1->relbit, REL_CNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) bitmap_zero(dev1->keybit, KEY_CNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) input_set_capability(dev1, EV_KEY, BTN_TOUCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (!desired_serio_phys) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) error = lifebook_create_relative_device(psmouse);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) lifebook_relative_mode(psmouse);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) psmouse->protocol_handler = lifebook_process_byte;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) psmouse->set_resolution = lifebook_set_resolution;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) psmouse->disconnect = lifebook_disconnect;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) psmouse->reconnect = lifebook_absolute_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) psmouse->model = lifebook_use_6byte_proto ? 6 : 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) * Use packet size = 3 even when using 6-byte protocol because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) * that's what POLL will return on Lifebooks (according to spec).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) psmouse->pktsize = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)