diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 69371779806a..f929fcdbae2e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -54,6 +54,19 @@ config TOUCHSCREEN_CORGI To compile this driver as a module, choose M here: the module will be called corgi_ts. +config TOUCHSCREEN_FUJITSU + tristate "Fujitsu serial touchscreen" + select SERIO + help + Say Y here if you have the Fujitsu touchscreen (such as one + installed in Lifebook P series laptop) connected to your + system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called fujitsu-ts. + config TOUCHSCREEN_GUNZE tristate "Gunze AHL-51S touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 2f86d6ad06d3..5de8933c4993 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o +obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c new file mode 100644 index 000000000000..daf7a4afc935 --- /dev/null +++ b/drivers/input/touchscreen/fujitsu_ts.c @@ -0,0 +1,189 @@ +/* + * Fujitsu serial touchscreen driver + * + * Copyright (c) Dmitry Torokhov + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Fujitsu serial touchscreen driver" + +MODULE_AUTHOR("Dmitry Torokhov "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +#define FUJITSU_LENGTH 5 + +/* + * Per-touchscreen data. + */ +struct fujitsu { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[FUJITSU_LENGTH]; + char phys[32]; +}; + +/* + * Decode serial data (5 bytes per packet) + * First byte + * 1 C 0 0 R S S S + * Where C is 1 while in calibration mode (which we don't use) + * R is 1 when no coordinate corection was done. + * S are button state + */ +static irqreturn_t fujitsu_interrupt(struct serio *serio, + unsigned char data, unsigned int flags) +{ + struct fujitsu *fujitsu = serio_get_drvdata(serio); + struct input_dev *dev = fujitsu->dev; + + if (fujitsu->idx == 0) { + /* resync skip until start of frame */ + if ((data & 0xf0) != 0x80) + return IRQ_HANDLED; + } else { + /* resync skip garbage */ + if (data & 0x80) { + fujitsu->idx = 0; + return IRQ_HANDLED; + } + } + + fujitsu->data[fujitsu->idx++] = data; + if (fujitsu->idx == FUJITSU_LENGTH) { + input_report_abs(dev, ABS_X, + (fujitsu->data[2] << 7) | fujitsu->data[1]); + input_report_abs(dev, ABS_Y, + (fujitsu->data[4] << 7) | fujitsu->data[3]); + input_report_key(dev, BTN_TOUCH, + (fujitsu->data[0] & 0x03) != 2); + input_sync(dev); + fujitsu->idx = 0; + } + + return IRQ_HANDLED; +} + +/* + * fujitsu_disconnect() is the opposite of fujitsu_connect() + */ +static void fujitsu_disconnect(struct serio *serio) +{ + struct fujitsu *fujitsu = serio_get_drvdata(serio); + + input_get_device(fujitsu->dev); + input_unregister_device(fujitsu->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(fujitsu->dev); + kfree(fujitsu); +} + +/* + * fujitsu_connect() is the routine that is called when someone adds a + * new serio device that supports the Fujitsu protocol and registers it + * as input device. + */ +static int fujitsu_connect(struct serio *serio, struct serio_driver *drv) +{ + struct fujitsu *fujitsu; + struct input_dev *input_dev; + int err; + + fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!fujitsu || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + fujitsu->serio = serio; + fujitsu->dev = input_dev; + snprintf(fujitsu->phys, sizeof(fujitsu->phys), + "%s/input0", serio->phys); + + input_dev->name = "Fujitsu Serial Touchscreen"; + input_dev->phys = fujitsu->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_FUJITSU; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0); + serio_set_drvdata(serio, fujitsu); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(fujitsu->dev); + if (err) + goto fail3; + + return 0; + + fail3: + serio_close(serio); + fail2: + serio_set_drvdata(serio, NULL); + fail1: + input_free_device(input_dev); + kfree(fujitsu); + return err; +} + +/* + * The serio driver structure. + */ +static struct serio_device_id fujitsu_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_FUJITSU, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids); + +static struct serio_driver fujitsu_drv = { + .driver = { + .name = "fujitsu_ts", + }, + .description = DRIVER_DESC, + .id_table = fujitsu_serio_ids, + .interrupt = fujitsu_interrupt, + .connect = fujitsu_connect, + .disconnect = fujitsu_disconnect, +}; + +static int __init fujitsu_init(void) +{ + return serio_register_driver(&fujitsu_drv); +} + +static void __exit fujitsu_exit(void) +{ + serio_unregister_driver(&fujitsu_drv); +} + +module_init(fujitsu_init); +module_exit(fujitsu_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index d9377ce9ffd1..9f3825014674 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -210,5 +210,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_TOUCHRIGHT 0x32 #define SERIO_TOUCHWIN 0x33 #define SERIO_TAOSEVM 0x34 +#define SERIO_FUJITSU 0x35 #endif