1 // SPDX-License-Identifier: GPL-2.0-only
3 * Dynapro serial touchscreen driver
5 * Copyright (c) 2009 Tias Guns
6 * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
12 * 2009/09/19 Tias Guns <tias@ulyssis.org>
13 * Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
16 #include <linux/errno.h>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/slab.h>
20 #include <linux/input.h>
21 #include <linux/serio.h>
23 #define DRIVER_DESC "Dynapro serial touchscreen driver"
25 MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
26 MODULE_DESCRIPTION(DRIVER_DESC
);
27 MODULE_LICENSE("GPL");
30 * Definitions & global arrays.
33 #define DYNAPRO_FORMAT_TOUCH_BIT 0x40
34 #define DYNAPRO_FORMAT_LENGTH 3
35 #define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
37 #define DYNAPRO_MIN_XC 0
38 #define DYNAPRO_MAX_XC 0x3ff
39 #define DYNAPRO_MIN_YC 0
40 #define DYNAPRO_MAX_YC 0x3ff
42 #define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
43 #define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
44 #define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
47 * Per-touchscreen data.
51 struct input_dev
*dev
;
54 unsigned char data
[DYNAPRO_FORMAT_LENGTH
];
58 static void dynapro_process_data(struct dynapro
*pdynapro
)
60 struct input_dev
*dev
= pdynapro
->dev
;
62 if (DYNAPRO_FORMAT_LENGTH
== ++pdynapro
->idx
) {
63 input_report_abs(dev
, ABS_X
, DYNAPRO_GET_XC(pdynapro
->data
));
64 input_report_abs(dev
, ABS_Y
, DYNAPRO_GET_YC(pdynapro
->data
));
65 input_report_key(dev
, BTN_TOUCH
,
66 DYNAPRO_GET_TOUCHED(pdynapro
->data
));
73 static irqreturn_t
dynapro_interrupt(struct serio
*serio
,
74 unsigned char data
, unsigned int flags
)
76 struct dynapro
*pdynapro
= serio_get_drvdata(serio
);
78 pdynapro
->data
[pdynapro
->idx
] = data
;
80 if (DYNAPRO_RESPONSE_BEGIN_BYTE
& pdynapro
->data
[0])
81 dynapro_process_data(pdynapro
);
83 dev_dbg(&serio
->dev
, "unknown/unsynchronized data: %x\n",
89 static void dynapro_disconnect(struct serio
*serio
)
91 struct dynapro
*pdynapro
= serio_get_drvdata(serio
);
93 input_get_device(pdynapro
->dev
);
94 input_unregister_device(pdynapro
->dev
);
96 serio_set_drvdata(serio
, NULL
);
97 input_put_device(pdynapro
->dev
);
102 * dynapro_connect() is the routine that is called when someone adds a
103 * new serio device that supports dynapro protocol and registers it as
104 * an input device. This is usually accomplished using inputattach.
107 static int dynapro_connect(struct serio
*serio
, struct serio_driver
*drv
)
109 struct dynapro
*pdynapro
;
110 struct input_dev
*input_dev
;
113 pdynapro
= kzalloc(sizeof(struct dynapro
), GFP_KERNEL
);
114 input_dev
= input_allocate_device();
115 if (!pdynapro
|| !input_dev
) {
120 pdynapro
->serio
= serio
;
121 pdynapro
->dev
= input_dev
;
122 snprintf(pdynapro
->phys
, sizeof(pdynapro
->phys
),
123 "%s/input0", serio
->phys
);
125 input_dev
->name
= "Dynapro Serial TouchScreen";
126 input_dev
->phys
= pdynapro
->phys
;
127 input_dev
->id
.bustype
= BUS_RS232
;
128 input_dev
->id
.vendor
= SERIO_DYNAPRO
;
129 input_dev
->id
.product
= 0;
130 input_dev
->id
.version
= 0x0001;
131 input_dev
->dev
.parent
= &serio
->dev
;
132 input_dev
->evbit
[0] = BIT_MASK(EV_KEY
) | BIT_MASK(EV_ABS
);
133 input_dev
->keybit
[BIT_WORD(BTN_TOUCH
)] = BIT_MASK(BTN_TOUCH
);
134 input_set_abs_params(pdynapro
->dev
, ABS_X
,
135 DYNAPRO_MIN_XC
, DYNAPRO_MAX_XC
, 0, 0);
136 input_set_abs_params(pdynapro
->dev
, ABS_Y
,
137 DYNAPRO_MIN_YC
, DYNAPRO_MAX_YC
, 0, 0);
139 serio_set_drvdata(serio
, pdynapro
);
141 err
= serio_open(serio
, drv
);
145 err
= input_register_device(pdynapro
->dev
);
151 fail3
: serio_close(serio
);
152 fail2
: serio_set_drvdata(serio
, NULL
);
153 fail1
: input_free_device(input_dev
);
159 * The serio driver structure.
162 static const struct serio_device_id dynapro_serio_ids
[] = {
165 .proto
= SERIO_DYNAPRO
,
172 MODULE_DEVICE_TABLE(serio
, dynapro_serio_ids
);
174 static struct serio_driver dynapro_drv
= {
178 .description
= DRIVER_DESC
,
179 .id_table
= dynapro_serio_ids
,
180 .interrupt
= dynapro_interrupt
,
181 .connect
= dynapro_connect
,
182 .disconnect
= dynapro_disconnect
,
185 module_serio_driver(dynapro_drv
);