From: Vojtech Pavlik <vojtech@suse.cz>
To: torvalds@osdl.org, vojtech@suse.cz, linux-kernel@vger.kernel.org
Subject: [PATCH 18/47] Updates to the tsdev driver (raw protocol, calib ioctls, ...)
Date: Thu, 29 Jul 2004 16:09:55 +0200 [thread overview]
Message-ID: <10911101952880@twilight.ucw.cz> (raw)
In-Reply-To: <10911101953746@twilight.ucw.cz>
You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input
===================================================================
ChangeSet@1.1722.117.5, 2004-06-06 11:56:42+02:00, zap@homelink.ru
input:
From: Andrew Zabolotny <zap@homelink.ru>
- Implement the 'raw' touchscreen protocol for backward compatibility
(/dev/input/ts[0-7] now speaks the protocol of the old /dev/h3600_ts, and
the /dev/input/tsraw[0-7] speaks the protocol of the old /dev/h3600_tsraw
device).
- Support the ioctls for setting the calibration parameters. The default
calibration matrix is computed from the xres,yres parameters (duplicate the
old behaviour), however this is not enough for a good translation from
touchscreen space to screen space.
- Fixed a old bug in tsdev: on a pen motion event X1,Y1 -> X2,Y2 the driver
would output three events with coordinates: X1,Y1, X2,Y1, X2,Y2. This
happened not only with coordinates, but with pressure too.
- Update James's email address
- Remove mention of Transvirtual Technologies: they no longer exist.
Signed-off-by: Vojtech Pavlik <vojtech@suse.cz>
tsdev.c | 291 ++++++++++++++++++++++++++++++++++++++++------------------------
1 files changed, 186 insertions(+), 105 deletions(-)
===================================================================
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c Thu Jul 29 14:40:58 2004
+++ b/drivers/input/tsdev.c Thu Jul 29 14:40:58 2004
@@ -3,9 +3,17 @@
*
* Copyright (c) 2001 "Crazy" james Simmons
*
- * Input driver to Touchscreen device driver module.
+ * Compaq touchscreen protocol driver. The protocol emulated by this driver
+ * is obsolete; for new programs use the tslib library which can read directly
+ * from evdev and perform dejittering, variance filtering and calibration -
+ * all in user space, not at kernel level. The meaning of this driver is
+ * to allow usage of newer input drivers with old applications that use the
+ * old /dev/h3600_ts and /dev/h3600_tsraw devices.
*
- * Sponsored by Transvirtual Technology
+ * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
+ * Fixed to actually work, not just output random numbers.
+ * Added support for both h3600_ts and h3600_tsraw protocol
+ * emulation.
*/
/*
@@ -24,11 +32,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <jsimmons@transvirtual.com>.
+ * e-mail - mail your message to <jsimmons@infradead.org>.
*/
#define TSDEV_MINOR_BASE 128
#define TSDEV_MINORS 32
+/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
+#define TSDEV_MINOR_MASK 15
#define TSDEV_BUFFER_SIZE 64
#include <linux/slab.h>
@@ -52,48 +62,84 @@
#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
#endif
+/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
+ * devices. The first one must output X/Y data in 'cooked' format, e.g.
+ * filtered, dejittered and calibrated. Second device just outputs raw
+ * data received from the hardware.
+ *
+ * This driver doesn't support filtering and dejittering; it supports only
+ * calibration. Filtering and dejittering must be done in the low-level
+ * driver, if needed, because it may gain additional benefits from knowing
+ * the low-level details, the nature of noise and so on.
+ *
+ * The driver precomputes a calibration matrix given the initial xres and
+ * yres values (quite innacurate for most touchscreens) that will result
+ * in a more or less expected range of output values. The driver supports
+ * the TS_SET_CAL ioctl, which will replace the calibration matrix with a
+ * new one, supposedly generated from the values taken from the raw device.
+ */
+
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("Input driver to touchscreen converter");
MODULE_LICENSE("GPL");
static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
module_param(xres, uint, 0);
-MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
module_param(yres, uint, 0);
-MODULE_PARM_DESC(yres, "Vertical screen resolution");
+MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
+
+/* From Compaq's Touch Screen Specification version 0.2 (draft) */
+struct ts_event {
+ short pressure;
+ short x;
+ short y;
+ short millisecs;
+};
+
+struct ts_calibration {
+ int xscale;
+ int xtrans;
+ int yscale;
+ int ytrans;
+ int xyswap;
+};
struct tsdev {
int exist;
int open;
int minor;
- char name[16];
+ char name[8];
wait_queue_head_t wait;
struct list_head list;
struct input_handle handle;
+ int x, y, pressure;
+ struct ts_calibration cal;
};
-/* From Compaq's Touch Screen Specification version 0.2 (draft) */
-typedef struct {
- short pressure;
- short x;
- short y;
- short millisecs;
-} TS_EVENT;
-
struct tsdev_list {
struct fasync_struct *fasync;
struct list_head node;
struct tsdev *tsdev;
int head, tail;
- int oldx, oldy, pendown;
- TS_EVENT event[TSDEV_BUFFER_SIZE];
+ struct ts_event event[TSDEV_BUFFER_SIZE];
+ int raw;
};
+/* The following ioctl codes are defined ONLY for backward compatibility.
+ * Don't use tsdev for new developement; use the tslib library instead.
+ * Touchscreen calibration is a fully userspace task.
+ */
+/* Use 'f' as magic number */
+#define IOC_H3600_TS_MAGIC 'f'
+#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
+#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
+
static struct input_handler tsdev_handler;
-static struct tsdev *tsdev_table[TSDEV_MINORS];
+static struct tsdev *tsdev_table[TSDEV_MINORS/2];
static int tsdev_fasync(int fd, struct file *file, int on)
{
@@ -109,13 +155,16 @@
int i = iminor(inode) - TSDEV_MINOR_BASE;
struct tsdev_list *list;
- if (i >= TSDEV_MINORS || !tsdev_table[i])
+ if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
return -ENODEV;
if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct tsdev_list));
+ list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
+
+ i &= TSDEV_MINOR_MASK;
list->tsdev = tsdev_table[i];
list_add_tail(&list->node, &tsdev_table[i]->list);
file->private_data = list;
@@ -169,11 +218,13 @@
if (!list->tsdev->exist)
return -ENODEV;
- while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) {
- if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT)))
+ while (list->head != list->tail &&
+ retval + sizeof (struct ts_event) <= count) {
+ if (copy_to_user (buffer + retval, list->event + list->tail,
+ sizeof (struct ts_event)))
return -EFAULT;
list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
- retval += sizeof(TS_EVENT);
+ retval += sizeof (struct ts_event);
}
return retval;
@@ -193,22 +244,27 @@
static int tsdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
-/*
struct tsdev_list *list = file->private_data;
- struct tsdev *evdev = list->tsdev;
- struct input_dev *dev = tsdev->handle.dev;
- int retval;
-
+ struct tsdev *tsdev = list->tsdev;
+ int retval = 0;
+
switch (cmd) {
- case HHEHE:
- return 0;
- case hjff:
- return 0;
- default:
- return 0;
+ case TS_GET_CAL:
+ if (copy_to_user ((void *)arg, &tsdev->cal,
+ sizeof (struct ts_calibration)))
+ retval = -EFAULT;
+ break;
+ case TS_SET_CAL:
+ if (copy_from_user (&tsdev->cal, (void *)arg,
+ sizeof (struct ts_calibration)))
+ retval = -EFAULT;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
}
-*/
- return -EINVAL;
+
+ return retval;
}
struct file_operations tsdev_fops = {
@@ -227,82 +283,85 @@
struct tsdev *tsdev = handle->private;
struct tsdev_list *list;
struct timeval time;
- int size;
- list_for_each_entry(list, &tsdev->list, node) {
- switch (type) {
- case EV_ABS:
- switch (code) {
- case ABS_X:
- if (!list->pendown)
- return;
- size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
- if (size > 0)
- list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size);
- else
- list->oldx = ((value - handle->dev->absmin[ABS_X]));
- break;
- case ABS_Y:
- if (!list->pendown)
- return;
- size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
- if (size > 0)
- list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size);
- else
- list->oldy = ((value - handle->dev->absmin[ABS_Y]));
- break;
- case ABS_PRESSURE:
- list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ?
- value - handle->dev->absmin[ABS_PRESSURE] : 0;
- break;
- }
+ switch (type) {
+ case EV_ABS:
+ switch (code) {
+ case ABS_X:
+ tsdev->x = value;
+ break;
+ case ABS_Y:
+ tsdev->y = value;
+ break;
+ case ABS_PRESSURE:
+ if (value > handle->dev->absmax[ABS_PRESSURE])
+ value = handle->dev->absmax[ABS_PRESSURE];
+ value -= handle->dev->absmin[ABS_PRESSURE];
+ if (value < 0)
+ value = 0;
+ tsdev->pressure = value;
+ break;
+ }
+ break;
+
+ case EV_REL:
+ switch (code) {
+ case REL_X:
+ tsdev->x += value;
+ if (tsdev->x < 0)
+ tsdev->x = 0;
+ else if (tsdev->x > xres)
+ tsdev->x = xres;
+ break;
+ case REL_Y:
+ tsdev->y += value;
+ if (tsdev->y < 0)
+ tsdev->y = 0;
+ else if (tsdev->y > yres)
+ tsdev->y = yres;
break;
+ }
+ break;
- case EV_REL:
- switch (code) {
- case REL_X:
- if (!list->pendown)
- return;
- list->oldx += value;
- if (list->oldx < 0)
- list->oldx = 0;
- else if (list->oldx > xres)
- list->oldx = xres;
+ case EV_KEY:
+ if (code == BTN_TOUCH || code == BTN_MOUSE) {
+ switch (value) {
+ case 0:
+ tsdev->pressure = 0;
break;
- case REL_Y:
- if (!list->pendown)
- return;
- list->oldy += value;
- if (list->oldy < 0)
- list->oldy = 0;
- else if (list->oldy > xres)
- list->oldy = xres;
+ case 1:
+ if (!tsdev->pressure)
+ tsdev->pressure = 1;
break;
}
- break;
-
- case EV_KEY:
- if (code == BTN_TOUCH || code == BTN_MOUSE) {
- switch (value) {
- case 0:
- list->pendown = 0;
- break;
- case 1:
- if (!list->pendown)
- list->pendown = 1;
- break;
- case 2:
- return;
- }
- } else
- return;
- break;
}
+ break;
+ }
+
+ if (type != EV_SYN || code != SYN_REPORT)
+ return;
+
+ list_for_each_entry(list, &tsdev->list, node) {
+ int x, y, tmp;
+
do_gettimeofday(&time);
list->event[list->head].millisecs = time.tv_usec / 100;
- list->event[list->head].pressure = list->pendown;
- list->event[list->head].x = list->oldx;
- list->event[list->head].y = list->oldy;
+ list->event[list->head].pressure = tsdev->pressure;
+
+ x = tsdev->x;
+ y = tsdev->y;
+
+ /* Calibration */
+ if (!list->raw) {
+ x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
+ y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
+ if (tsdev->cal.xyswap) {
+ tmp = x; x = y; y = tmp;
+ }
+ }
+
+ list->event[list->head].x = x;
+ list->event[list->head].y = y;
list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
@@ -314,11 +373,11 @@
struct input_device_id *id)
{
struct tsdev *tsdev;
- int minor;
+ int minor, delta;
- for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
+ for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor];
minor++);
- if (minor == TSDEV_MINORS) {
+ if (minor >= TSDEV_MINORS/2) {
printk(KERN_ERR
"tsdev: You have way too many touchscreens\n");
return NULL;
@@ -340,10 +399,25 @@
tsdev->handle.handler = handler;
tsdev->handle.private = tsdev;
+ /* Precompute the rough calibration matrix */
+ delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
+ if (delta == 0)
+ delta = 1;
+ tsdev->cal.xscale = (xres << 8) / delta;
+ tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
+
+ delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
+ if (delta == 0)
+ delta = 1;
+ tsdev->cal.yscale = (yres << 8) / delta;
+ tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
+
tsdev_table[minor] = tsdev;
-
+
devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
+ devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2),
+ S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor);
class_simple_device_add(input_class,
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
dev->dev, "ts%d", minor);
@@ -362,6 +436,7 @@
wake_up_interruptible(&tsdev->wait);
} else
tsdev_free(tsdev);
+ devfs_remove("input/tsraw%d", tsdev->minor);
}
static struct input_device_id tsdev_ids[] = {
@@ -378,6 +453,12 @@
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
},/* A tablet like device, at least touch detection, two absolute axes */
+
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT(EV_ABS) },
+ .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
+ },/* A tablet like device with several gradations of pressure */
{},/* Terminating entry */
};
next prev parent reply other threads:[~2004-07-29 14:51 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-07-29 14:07 [patches] Input updates Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 1/47] Add 64-bit compatible ioctls for hiddev Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 2/47] Fix locking in i8042.c and serio.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 3/47] Fix an oops in poll() on uinput Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 4/47] Ensure exclusive access to variables in atkbd.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 5/47] Return 0 from uinput poll if device isn't yet created Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 6/47] Explicit variable access rules for psmouse.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 7/47] Add reporting of raw scancodes to atkbd.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 8/47] Use raw events generated by atkbd in keyboard.c to implement true rawmode for PS/2 keyboards Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 9/47] Fixes in serio locking Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 10/47] Disable the AUX LoopBack command in i8042.c on Compaq ProLiant Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 11/47] Make atkbd.c's atkbd_command() function immune to keys being pressed while running Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 12/47] More locking improvements (and a fix) for serio Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 13/47] Add a missing dmi_noloop declaration in i8042.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 14/47] logips2pp - do not call get_model_info 2 times Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 15/47] Fix compilation breakage when CONFIG_USB_HIDDEV not defined Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 16/47] Make hardware rawmode optional for AT-keyboards Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 17/47] Fix boundary checks for GUSAGE/SUSAGE in hiddev Vojtech Pavlik
2004-07-29 14:09 ` Vojtech Pavlik [this message]
2004-07-29 14:09 ` [PATCH 19/47] mousedev - better handle button presses when under load Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 20/47] mousedev - implement tapping for touchpads Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 21/47] Remove OSB4/Profusion hack in i8042 Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 22/47] rearrangements and cleanups in serio.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 23/47] Fix bad struct hidinput initialization in hid-tmff.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 24/47] Remove an extra dmi_noloop declaration in i8042.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 25/47] Enhancements/fixes for PSX pad support Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 26/47] when probing for ImExPS/2 mice, the ImPS/2 sequence needs to be sent first Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 27/47] Fix array overflows in keyboard.c when KEY_MAX > keycode > NR_KEYS > 128 Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 28/47] Add Dell SB Live! PCI ID to the emu10k1-gp driver Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 29/47] Add Audigy LS PCI ID to emu10k1-gp Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 30/47] Add CodeMercs IOWarrior to hid-core device blacklist Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 31/47] Fix Peter Nelson's e-mail address in gamecon.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 32/47] make connect and disconnect methods mandatory for serio Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 33/47] rename serio->driver to serio->port_data Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 34/47] more renames in serio in preparation for sysfs integration Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 35/47] switch to dynamic (heap) serio port allocation Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 36/47] allow serio drivers to create children ports Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 37/47] serio sysfs integration Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 38/47] allow users to manually rebind serio ports Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 39/47] allow marking some drivers as manual bind only Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 40/47] Add serio_raw driver Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 41/47] link (some) serio ports to their parent devices Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 42/47] Fix Kconfig so that the joydump module can be compiled Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 43/47] Move Compaq ProLiant DMI handling to i8042.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 44/47] This patch fixes another disconnect oops in hiddev Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 45/47] Re-add PC Speaker support for PPC Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 46/47] Fix a missing index in tmdc.c Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 47/47] Check the range for HIDIOC?USAGES num_values Vojtech Pavlik
2004-07-29 16:59 ` [patches] Input updates Vojtech Pavlik
2004-07-29 16:59 ` [PATCH 1/2] move input/serio closer to the top of drivers/Makefile so serio_bus is available early Vojtech Pavlik
2004-07-29 16:59 ` [PATCH 2/2] rearrange code in sunzilog to prevent deadlock Vojtech Pavlik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=10911101952880@twilight.ucw.cz \
--to=vojtech@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.