1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
211ea3173SRick Koch /*
311ea3173SRick Koch  * Touchwindow serial touchscreen driver
411ea3173SRick Koch  *
511ea3173SRick Koch  * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
611ea3173SRick Koch  *
711ea3173SRick Koch  * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
811ea3173SRick Koch  * Copyright (c) 2004 Vojtech Pavlik
911ea3173SRick Koch  * and Dan Streetman <ddstreet@ieee.org>
1011ea3173SRick Koch  */
1111ea3173SRick Koch 
1211ea3173SRick Koch 
1311ea3173SRick Koch /*
1411ea3173SRick Koch  * 2005/02/19 Rick Koch:
1511ea3173SRick Koch  *   The Touchwindow I used is made by Edmark Corp. and
1611ea3173SRick Koch  *   constantly outputs a stream of 0's unless it is touched.
1711ea3173SRick Koch  *   It then outputs 3 bytes: X, Y, and a copy of Y.
1811ea3173SRick Koch  */
1911ea3173SRick Koch 
2011ea3173SRick Koch #include <linux/errno.h>
2111ea3173SRick Koch #include <linux/kernel.h>
2211ea3173SRick Koch #include <linux/module.h>
2311ea3173SRick Koch #include <linux/slab.h>
2411ea3173SRick Koch #include <linux/input.h>
2511ea3173SRick Koch #include <linux/serio.h>
2611ea3173SRick Koch 
2711ea3173SRick Koch #define DRIVER_DESC	"Touchwindow serial touchscreen driver"
2811ea3173SRick Koch 
2911ea3173SRick Koch MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
3011ea3173SRick Koch MODULE_DESCRIPTION(DRIVER_DESC);
3111ea3173SRick Koch MODULE_LICENSE("GPL");
3211ea3173SRick Koch 
3311ea3173SRick Koch /*
3411ea3173SRick Koch  * Definitions & global arrays.
3511ea3173SRick Koch  */
3611ea3173SRick Koch 
3711ea3173SRick Koch #define TW_LENGTH 3
3811ea3173SRick Koch 
3911ea3173SRick Koch #define TW_MIN_XC 0
4011ea3173SRick Koch #define TW_MAX_XC 0xff
4111ea3173SRick Koch #define TW_MIN_YC 0
4211ea3173SRick Koch #define TW_MAX_YC 0xff
4311ea3173SRick Koch 
4411ea3173SRick Koch /*
4511ea3173SRick Koch  * Per-touchscreen data.
4611ea3173SRick Koch  */
4711ea3173SRick Koch 
4811ea3173SRick Koch struct tw {
4911ea3173SRick Koch 	struct input_dev *dev;
5011ea3173SRick Koch 	struct serio *serio;
5111ea3173SRick Koch 	int idx;
5211ea3173SRick Koch 	int touched;
5311ea3173SRick Koch 	unsigned char data[TW_LENGTH];
5411ea3173SRick Koch 	char phys[32];
5511ea3173SRick Koch };
5611ea3173SRick Koch 
tw_interrupt(struct serio * serio,unsigned char data,unsigned int flags)5711ea3173SRick Koch static irqreturn_t tw_interrupt(struct serio *serio,
587d12e780SDavid Howells 		unsigned char data, unsigned int flags)
5911ea3173SRick Koch {
6011ea3173SRick Koch 	struct tw *tw = serio_get_drvdata(serio);
6111ea3173SRick Koch 	struct input_dev *dev = tw->dev;
6211ea3173SRick Koch 
6311ea3173SRick Koch 	if (data) {		/* touch */
6411ea3173SRick Koch 		tw->touched = 1;
6511ea3173SRick Koch 		tw->data[tw->idx++] = data;
6611ea3173SRick Koch 		/* verify length and that the two Y's are the same */
6711ea3173SRick Koch 		if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) {
6811ea3173SRick Koch 			input_report_abs(dev, ABS_X, tw->data[0]);
6911ea3173SRick Koch 			input_report_abs(dev, ABS_Y, tw->data[1]);
7011ea3173SRick Koch 			input_report_key(dev, BTN_TOUCH, 1);
7111ea3173SRick Koch 			input_sync(dev);
7211ea3173SRick Koch 			tw->idx = 0;
7311ea3173SRick Koch 		}
7411ea3173SRick Koch 	} else if (tw->touched) {	/* untouch */
7511ea3173SRick Koch 		input_report_key(dev, BTN_TOUCH, 0);
7611ea3173SRick Koch 		input_sync(dev);
7711ea3173SRick Koch 		tw->idx = 0;
7811ea3173SRick Koch 		tw->touched = 0;
7911ea3173SRick Koch 	}
8011ea3173SRick Koch 
8111ea3173SRick Koch 	return IRQ_HANDLED;
8211ea3173SRick Koch }
8311ea3173SRick Koch 
8411ea3173SRick Koch /*
8511ea3173SRick Koch  * tw_disconnect() is the opposite of tw_connect()
8611ea3173SRick Koch  */
8711ea3173SRick Koch 
tw_disconnect(struct serio * serio)8811ea3173SRick Koch static void tw_disconnect(struct serio *serio)
8911ea3173SRick Koch {
9011ea3173SRick Koch 	struct tw *tw = serio_get_drvdata(serio);
9111ea3173SRick Koch 
9211ea3173SRick Koch 	input_get_device(tw->dev);
9311ea3173SRick Koch 	input_unregister_device(tw->dev);
9411ea3173SRick Koch 	serio_close(serio);
9511ea3173SRick Koch 	serio_set_drvdata(serio, NULL);
9611ea3173SRick Koch 	input_put_device(tw->dev);
9711ea3173SRick Koch 	kfree(tw);
9811ea3173SRick Koch }
9911ea3173SRick Koch 
10011ea3173SRick Koch /*
10111ea3173SRick Koch  * tw_connect() is the routine that is called when someone adds a
10211ea3173SRick Koch  * new serio device that supports the Touchwin protocol and registers it as
10311ea3173SRick Koch  * an input device.
10411ea3173SRick Koch  */
10511ea3173SRick Koch 
tw_connect(struct serio * serio,struct serio_driver * drv)10611ea3173SRick Koch static int tw_connect(struct serio *serio, struct serio_driver *drv)
10711ea3173SRick Koch {
10811ea3173SRick Koch 	struct tw *tw;
10911ea3173SRick Koch 	struct input_dev *input_dev;
11011ea3173SRick Koch 	int err;
11111ea3173SRick Koch 
11211ea3173SRick Koch 	tw = kzalloc(sizeof(struct tw), GFP_KERNEL);
11311ea3173SRick Koch 	input_dev = input_allocate_device();
11411ea3173SRick Koch 	if (!tw || !input_dev) {
11511ea3173SRick Koch 		err = -ENOMEM;
11611ea3173SRick Koch 		goto fail1;
11711ea3173SRick Koch 	}
11811ea3173SRick Koch 
11911ea3173SRick Koch 	tw->serio = serio;
12011ea3173SRick Koch 	tw->dev = input_dev;
12111ea3173SRick Koch 	snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
12211ea3173SRick Koch 
12311ea3173SRick Koch 	input_dev->name = "Touchwindow Serial TouchScreen";
12411ea3173SRick Koch 	input_dev->phys = tw->phys;
12511ea3173SRick Koch 	input_dev->id.bustype = BUS_RS232;
12611ea3173SRick Koch 	input_dev->id.vendor = SERIO_TOUCHWIN;
12711ea3173SRick Koch 	input_dev->id.product = 0;
12811ea3173SRick Koch 	input_dev->id.version = 0x0100;
129a5394fb0SDmitry Torokhov 	input_dev->dev.parent = &serio->dev;
1307b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
1317b19ada2SJiri Slaby 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
13211ea3173SRick Koch 	input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
13311ea3173SRick Koch 	input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0);
13411ea3173SRick Koch 
13511ea3173SRick Koch 	serio_set_drvdata(serio, tw);
13611ea3173SRick Koch 
13711ea3173SRick Koch 	err = serio_open(serio, drv);
13811ea3173SRick Koch 	if (err)
13911ea3173SRick Koch 		goto fail2;
14011ea3173SRick Koch 
14111ea3173SRick Koch 	err = input_register_device(tw->dev);
14211ea3173SRick Koch 	if (err)
14311ea3173SRick Koch 		goto fail3;
14411ea3173SRick Koch 
14511ea3173SRick Koch 	return 0;
14611ea3173SRick Koch 
14711ea3173SRick Koch  fail3:	serio_close(serio);
14811ea3173SRick Koch  fail2:	serio_set_drvdata(serio, NULL);
14911ea3173SRick Koch  fail1:	input_free_device(input_dev);
15011ea3173SRick Koch 	kfree(tw);
15111ea3173SRick Koch 	return err;
15211ea3173SRick Koch }
15311ea3173SRick Koch 
15411ea3173SRick Koch /*
15511ea3173SRick Koch  * The serio driver structure.
15611ea3173SRick Koch  */
15711ea3173SRick Koch 
158a110a953SArvind Yadav static const struct serio_device_id tw_serio_ids[] = {
15911ea3173SRick Koch 	{
16011ea3173SRick Koch 		.type	= SERIO_RS232,
16111ea3173SRick Koch 		.proto	= SERIO_TOUCHWIN,
16211ea3173SRick Koch 		.id	= SERIO_ANY,
16311ea3173SRick Koch 		.extra	= SERIO_ANY,
16411ea3173SRick Koch 	},
16511ea3173SRick Koch 	{ 0 }
16611ea3173SRick Koch };
16711ea3173SRick Koch 
16811ea3173SRick Koch MODULE_DEVICE_TABLE(serio, tw_serio_ids);
16911ea3173SRick Koch 
17011ea3173SRick Koch static struct serio_driver tw_drv = {
17111ea3173SRick Koch 	.driver		= {
17211ea3173SRick Koch 		.name	= "touchwin",
17311ea3173SRick Koch 	},
17411ea3173SRick Koch 	.description	= DRIVER_DESC,
17511ea3173SRick Koch 	.id_table	= tw_serio_ids,
17611ea3173SRick Koch 	.interrupt	= tw_interrupt,
17711ea3173SRick Koch 	.connect	= tw_connect,
17811ea3173SRick Koch 	.disconnect	= tw_disconnect,
17911ea3173SRick Koch };
18011ea3173SRick Koch 
18165ac9f7aSAxel Lin module_serio_driver(tw_drv);
182