cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lifebook.c (8082B)


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