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

fujitsu_ts.c (3936B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Fujitsu serial touchscreen driver
      4 *
      5 * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
      6 */
      7
      8
      9#include <linux/errno.h>
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/slab.h>
     13#include <linux/input.h>
     14#include <linux/serio.h>
     15
     16#define DRIVER_DESC	"Fujitsu serial touchscreen driver"
     17
     18MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
     19MODULE_DESCRIPTION(DRIVER_DESC);
     20MODULE_LICENSE("GPL");
     21
     22#define FUJITSU_LENGTH 5
     23
     24/*
     25 * Per-touchscreen data.
     26 */
     27struct fujitsu {
     28	struct input_dev *dev;
     29	struct serio *serio;
     30	int idx;
     31	unsigned char data[FUJITSU_LENGTH];
     32	char phys[32];
     33};
     34
     35/*
     36 * Decode serial data (5 bytes per packet)
     37 * First byte
     38 * 1 C 0 0 R S S S
     39 * Where C is 1 while in calibration mode (which we don't use)
     40 * R is 1 when no coordinate corection was done.
     41 * S are button state
     42 */
     43static irqreturn_t fujitsu_interrupt(struct serio *serio,
     44				     unsigned char data, unsigned int flags)
     45{
     46	struct fujitsu *fujitsu = serio_get_drvdata(serio);
     47	struct input_dev *dev = fujitsu->dev;
     48
     49	if (fujitsu->idx == 0) {
     50		/* resync skip until start of frame */
     51		if ((data & 0xf0) != 0x80)
     52			return IRQ_HANDLED;
     53	} else {
     54		/* resync skip garbage */
     55		if (data & 0x80) {
     56			fujitsu->idx = 0;
     57			return IRQ_HANDLED;
     58		}
     59	}
     60
     61	fujitsu->data[fujitsu->idx++] = data;
     62	if (fujitsu->idx == FUJITSU_LENGTH) {
     63		input_report_abs(dev, ABS_X,
     64				 (fujitsu->data[2] << 7) | fujitsu->data[1]);
     65		input_report_abs(dev, ABS_Y,
     66				 (fujitsu->data[4] << 7) | fujitsu->data[3]);
     67		input_report_key(dev, BTN_TOUCH,
     68				 (fujitsu->data[0] & 0x03) != 2);
     69		input_sync(dev);
     70		fujitsu->idx = 0;
     71	}
     72
     73	return IRQ_HANDLED;
     74}
     75
     76/*
     77 * fujitsu_disconnect() is the opposite of fujitsu_connect()
     78 */
     79static void fujitsu_disconnect(struct serio *serio)
     80{
     81	struct fujitsu *fujitsu = serio_get_drvdata(serio);
     82
     83	input_get_device(fujitsu->dev);
     84	input_unregister_device(fujitsu->dev);
     85	serio_close(serio);
     86	serio_set_drvdata(serio, NULL);
     87	input_put_device(fujitsu->dev);
     88	kfree(fujitsu);
     89}
     90
     91/*
     92 * fujitsu_connect() is the routine that is called when someone adds a
     93 * new serio device that supports the Fujitsu protocol and registers it
     94 * as input device.
     95 */
     96static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
     97{
     98	struct fujitsu *fujitsu;
     99	struct input_dev *input_dev;
    100	int err;
    101
    102	fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
    103	input_dev = input_allocate_device();
    104	if (!fujitsu || !input_dev) {
    105		err = -ENOMEM;
    106		goto fail1;
    107	}
    108
    109	fujitsu->serio = serio;
    110	fujitsu->dev = input_dev;
    111	snprintf(fujitsu->phys, sizeof(fujitsu->phys),
    112		 "%s/input0", serio->phys);
    113
    114	input_dev->name = "Fujitsu Serial Touchscreen";
    115	input_dev->phys = fujitsu->phys;
    116	input_dev->id.bustype = BUS_RS232;
    117	input_dev->id.vendor = SERIO_FUJITSU;
    118	input_dev->id.product = 0;
    119	input_dev->id.version = 0x0100;
    120	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    121	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    122
    123	input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
    124	input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
    125	serio_set_drvdata(serio, fujitsu);
    126
    127	err = serio_open(serio, drv);
    128	if (err)
    129		goto fail2;
    130
    131	err = input_register_device(fujitsu->dev);
    132	if (err)
    133		goto fail3;
    134
    135	return 0;
    136
    137 fail3:
    138	serio_close(serio);
    139 fail2:
    140	serio_set_drvdata(serio, NULL);
    141 fail1:
    142	input_free_device(input_dev);
    143	kfree(fujitsu);
    144	return err;
    145}
    146
    147/*
    148 * The serio driver structure.
    149 */
    150static const struct serio_device_id fujitsu_serio_ids[] = {
    151	{
    152		.type	= SERIO_RS232,
    153		.proto	= SERIO_FUJITSU,
    154		.id	= SERIO_ANY,
    155		.extra	= SERIO_ANY,
    156	},
    157	{ 0 }
    158};
    159
    160MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
    161
    162static struct serio_driver fujitsu_drv = {
    163	.driver		= {
    164		.name	= "fujitsu_ts",
    165	},
    166	.description	= DRIVER_DESC,
    167	.id_table	= fujitsu_serio_ids,
    168	.interrupt	= fujitsu_interrupt,
    169	.connect	= fujitsu_connect,
    170	.disconnect	= fujitsu_disconnect,
    171};
    172
    173module_serio_driver(fujitsu_drv);