2004-04-21 06:51:29

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: /dev/psaux-Interface

On Wednesday 21 April 2004 01:31 am, Sau Dan Lee wrote:
> >>>>> "Dmitry" == Dmitry Torokhov <[email protected]> writes:
>
> Dmitry> It seems that the driver allows non-exclusive access to
> Dmitry> the port - multiple users may fight to set up the
> Dmitry> mode.
>
> That's wrong. The driver is written so that multiple processes can
> hold the device node open at the same time, in the same way /dev/psaux
> in pre2.6 kernels was.
>

Don't we say the same thing?

>
> Dmitry> How they will agree on which one to set?
>
> GPM and XFree86 have been coordinating themselves well on this on all
> my Linux systems since 1993. And this has continued to be so with my
> psaux Module on Linux 2.6.

Not all the world is GPM and XFree.

>
>
> Dmitry> On the other hand I do not want psaux to give me only
> Dmitry> exclusive access as I have had emough of GPM repeater
> Dmitry> feeding X feeding Y ... etc.
>
> Both GPM and XFree86 are aware of vc switching, I suppose.

Not all the world is GPM and XFree.

>
>
> Dmitry> It does not support active multiplexing controller (4 AUX
> Dmitry> ports) which becomes quite common and is the only sane
> Dmitry> option when you have several mice of different types.
>
> That's because I don't have such a thing, and the interface of serio.c
> is not documented. Instead of guessing how the interface is supposed
> to work, I think it's better to leave it to the kernel developers.

The question was whether to include it in the kernel as it is. If it is not
compled work then it should wait a bit.

>
>
> Dmitry> Also I do not see where the code makes sure that it does
> Dmitry> not bind to keyboard's port (so keyboard driver has to be
> Dmitry> loaded first).
>
> Ask the people who wrote i8042.c and serio.c to document the
> interface. I simply copied the necessary stuff from psmouse-base.c.
> If that psmouse.ko works, then why should my psaux fail?
>

Because if you look in psmouse_probe we actually check if there is a mouse
behing the port.

>
> Dmitry> I think the right way is to fix the issues with psmouse
> Dmitry> driver and use input system to tie all hardware together.
>
> But how can you add support of new protocols and hardware? Not
> everyone want to reimplement GPM and XFree86 drivers in kernel space.
> It's much easier to do it in user space. Adding the complexity of
> various devices and protocols into kernelspace is insane.
>

The thing is that processing in kernel space is not that complex. The only
thing kernel has to do is to parse raw data and convert to events. The events
are parsed by user space daemon with all required bells and whistles. See
for example Synaptics driver for Xfree86 by Peter Osterlund, or my GPM
patches for that matter.

Mousedev is a transitional thing, it will go away eventually or will have a
very limited use by legacy applications.

> The only sane way to do it, IMO, is to restructure the input layer
> slightly, so that mouse protocols are handled by userspace daemons.
> The daemon(s) are responsible for talking to the device directly via
> device nodes such as /dev/misc/psaux_direct, and translating these
> into the common protocol (IMPS2?) and hand it back to kernel space
> (via a special device node). The kernel can then combine the data
> from all daemons and repeat it on /dev/input/mice.
>

We have such thing - look at uinput module - it can be used to feed events
back into the kernel.

--
Dmitry


2004-04-21 07:15:59

by Sau Dan Lee

[permalink] [raw]
Subject: Re: /dev/psaux-Interface

>>>>> "Dmitry" == Dmitry Torokhov <[email protected]> writes:

Dmitry> Also I do not see where the code makes sure that it does
Dmitry> not bind to keyboard's port (so keyboard driver has to be
Dmitry> loaded first).
>> Ask the people who wrote i8042.c and serio.c to document the
>> interface. I simply copied the necessary stuff from
>> psmouse-base.c. If that psmouse.ko works, then why should my
>> psaux fail?

Dmitry> Because if you look in psmouse_probe we actually check if
Dmitry> there is a mouse behing the port.

Such probing can only detect my touchscreen (and many other devices)
as a PS2 mouse, due to hardware emulation. Why would I use Linux 2.6
if my touchscreen is degenerated into a mouse-emulating device?


>> Adding the complexity of various devices and protocols into
>> kernelspace is insane.

Dmitry> The thing is that processing in kernel space is not that
Dmitry> complex.

Even so, it's not easy to get it right. In kernel programming, you
have to take care of many issues, such as whether you have a process
context, when to use spinlock, wait queues, etc. I even had to care
about fasync() when developing the psaux module, even though it's just
copying a few lines of sample code from the kernel hacking guide.

If it were in user space, it would be simpler: I just need to open
/dev/psaux (a la 2.4, 2.2, 2.0, 1.0.32(?)), block-reading a byte,
modify the state of my state machine in the program, and output
something to a repeater device when needed. No SMP issues, fasync,
etc (assuming /dev/psaux and the repeater device do those
automagically).


Dmitry> The only thing kernel has to do is to parse raw data and
Dmitry> convert to events.

Unfortunately, it loses data during the conversion. Moreover, the
current /dev/psaux in standard 2.6 kernel DOES NOT ALLOW writing
command bytes to the PS2/AUX port, preventing me from enabling the
touchscreen behaviour (disabling mouse emulation) without any kernel
programming. That's stupid.

IOW, the 2.6 kernel is implementing a policy, taking away flexibility.


Dmitry> We have such thing - look at uinput module - it can be
Dmitry> used to feed events back into the kernel.

There is still no provision for a userspace program to talk to the PS2
AUX port *directly*. I don't want my commands to be censored and the
data be translated.


--
Sau Dan LEE ???u??(Big5) ~{@nJX6X~}(HZ)

E-mail: [email protected]
Home page: http://www.informatik.uni-freiburg.de/~danlee

2004-04-22 06:39:22

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: /dev/psaux-Interface

On Wednesday 21 April 2004 02:15 am, Sau Dan Lee wrote:
> >>>>> "Dmitry" == Dmitry Torokhov <[email protected]> writes:
>
>
> >> Adding the complexity of various devices and protocols into
> >> kernelspace is insane.
>
> Dmitry> The thing is that processing in kernel space is not that
> Dmitry> complex.
>
> Even so, it's not easy to get it right. In kernel programming, you
> have to take care of many issues, such as whether you have a process
> context, when to use spinlock, wait queues, etc. I even had to care
> about fasync() when developing the psaux module, even though it's just
> copying a few lines of sample code from the kernel hacking guide.
>

OK, here you go. It is the first cut. The driver creates an absolute device
for the touchscreen and a fake pass-through port to for the pointing device
which works in relative mode. All fancy stuff can be done in userspace via
evdev.

Hopefully I got Y-axis direction correctly and init sequence may need some
work. It also hijacks proto=imsp parameter until I merge Kim's protocol
selection changes. I wish I could test it but I do not have a Lifebook so
comments and suggestions are welcome.

Apply on top of patches in:
http://www.geocities.com/dt_or/input/2.6.6-rc2/

--
Dmitry

===== drivers/input/mouse/Makefile 1.9 vs edited =====
--- 1.9/drivers/input/mouse/Makefile Wed Mar 3 11:17:04 2004
+++ edited/drivers/input/mouse/Makefile Thu Apr 22 00:20:31 2004
@@ -15,4 +15,4 @@
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o

-psmouse-objs := psmouse-base.o logips2pp.o synaptics.o
+psmouse-objs := psmouse-base.o lbtouch.o logips2pp.o synaptics.o
===== drivers/input/mouse/psmouse-base.c 1.57 vs edited =====
--- 1.57/drivers/input/mouse/psmouse-base.c Tue Apr 20 23:59:36 2004
+++ edited/drivers/input/mouse/psmouse-base.c Thu Apr 22 00:59:31 2004
@@ -21,6 +21,7 @@
#include "psmouse.h"
#include "synaptics.h"
#include "logips2pp.h"
+#include "lbtouch.h"

MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");
MODULE_DESCRIPTION("PS/2 mouse driver");
@@ -53,7 +54,7 @@
__obsolete_setup("psmouse_resetafter=");
__obsolete_setup("psmouse_rate=");

-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "LBPS/2" };

/*
* psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -414,6 +415,15 @@
unsigned int max_proto, int set_properties)
{
int synaptics_hardware = 0;
+
+ if (max_proto == PSMOUSE_IMEX && lbtouch_init(psmouse, set_properties)) {
+ if (set_properties) {
+ psmouse->vendor = "Fujitsu";
+ psmouse->name = "Lifebook Touchscreen";
+ }
+
+ return PSMOUSE_LBTOUCH;
+ }

/*
* Try Synaptics TouchPad
===== drivers/input/mouse/psmouse.h 1.10 vs edited =====
--- 1.10/drivers/input/mouse/psmouse.h Tue Apr 20 17:42:10 2004
+++ edited/drivers/input/mouse/psmouse.h Thu Apr 22 00:14:52 2004
@@ -72,6 +72,7 @@
#define PSMOUSE_IMPS 5
#define PSMOUSE_IMEX 6
#define PSMOUSE_SYNAPTICS 7
+#define PSMOUSE_LBTOUCH 8

int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
===== drivers/input/mouse/lbtouch.c 1.0 vs 1.1 =====
--- /dev/null Fri Aug 30 18:31:37 2002
+++ 1.1/drivers/input/mouse/lbtouch.c Thu Apr 22 01:21:26 2004
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2004 Dmitry Torokhov <[email protected]>
+ */
+
+/*
+ * Lifebook touchscreen driver for Linux
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+#include "psmouse.h"
+#include "lbtouch.h"
+
+MODULE_AUTHOR("Dmitry Torokhov <[email protected]>");
+MODULE_DESCRIPTION("Fujitsu Lifebook touchscreen driver");
+MODULE_LICENSE("GPL");
+
+/* The default values are taken from Kenan Esau's driver */
+static int limits[4] = { 86, 955, 37, 937 };
+static int num_limits __initdata = 0;
+module_param_array_named(lbt_size, limits, int, num_limits, 0);
+MODULE_PARM_DESC(lbt_size, "Effective usable area of Lifebook touchscreen (left,right,bottom,up)");
+
+
+/*****************************************************************************
+ * Lifebook pass-through PS/2 port support
+ ****************************************************************************/
+static int lbtouch_pt_write(struct serio *port, unsigned char c)
+{
+ switch (c) {
+ case PSMOUSE_CMD_RESET_BAT & 0xff:
+ serio_interrupt(port, PSMOUSE_RET_ACK, 0, NULL);
+ serio_interrupt(port, PSMOUSE_RET_BAT, 0, NULL);
+ serio_interrupt(port, PSMOUSE_RET_ID, 0, NULL);
+ break;
+
+ case PSMOUSE_CMD_GETID & 0xff:
+ serio_interrupt(port, PSMOUSE_RET_ACK, 0, NULL);
+ serio_interrupt(port, 0x00, 0, NULL);
+ break;
+
+ case PSMOUSE_CMD_ENABLE & 0xff:
+ case PSMOUSE_CMD_RESET_DIS & 0xff:
+ serio_interrupt(port, PSMOUSE_RET_ACK, 0, NULL);
+ break;
+
+ default:
+ serio_interrupt(port, PSMOUSE_RET_NAK, 0, NULL);
+ break;
+ }
+
+ return 0;
+}
+
+static void lbtouch_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+{
+ struct psmouse *child = ptport->private;
+
+ if (child && child->state == PSMOUSE_ACTIVATED) {
+ serio_interrupt(ptport, packet[0], 0, NULL);
+ serio_interrupt(ptport, packet[1], 0, NULL);
+ serio_interrupt(ptport, packet[2], 0, NULL);
+ }
+}
+
+static void lbtouch_pt_create(struct psmouse *psmouse)
+{
+ struct psmouse_ptport *port;
+
+ psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL);
+ if (!port) {
+ printk(KERN_ERR "lbtouch: not enough memory to allocate pass-through port\n");
+ return;
+ }
+
+ memset(port, 0, sizeof(struct psmouse_ptport));
+
+ port->serio.type = SERIO_PS_PSTHRU;
+ port->serio.name = "Lifebook pass-through";
+ port->serio.phys = "lbtouch-pt/serio0";
+ port->serio.write = lbtouch_pt_write;
+ port->serio.driver = psmouse;
+}
+
+/*****************************************************************************
+ * Functions to interpret the absolute mode packets
+ ****************************************************************************/
+
+static psmouse_ret_t lbtouch_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+ struct input_dev *dev = &psmouse->dev;
+ unsigned char *p = psmouse->packet;
+ int x, y, touch;
+
+ input_regs(dev, regs);
+
+ if (psmouse->pktcnt < 3)
+ return PSMOUSE_GOOD_DATA;
+
+ if (p[0] & 0x80) {
+ x = ((unsigned int)(p[0] & 0x30) << 4) + p[1];
+ y = ((unsigned int)(p[0] & 0xc0) << 2) + p[2];
+ touch = p[0] & 0x04 ? 1 : 0;
+
+ input_report_key(dev, BTN_TOUCH, touch);
+ if (touch) {
+ input_report_abs(dev, ABS_X, x - limits[0]);
+ input_report_abs(dev, ABS_Y, limits[3] + limits[3] - y);
+ }
+
+ if ((p[0] &= 0x03) != 0 && psmouse->ptport && psmouse->ptport->serio.dev) {
+ p[1] = p[2] = 0;
+ lbtouch_pass_pt_packet(&psmouse->ptport->serio, p);
+ }
+ } else if (psmouse->ptport && psmouse->ptport->serio.dev) {
+ lbtouch_pass_pt_packet(&psmouse->ptport->serio, p);
+ }
+
+ return PSMOUSE_FULL_PACKET;
+}
+
+/*****************************************************************************
+ * Driver initialization/cleanup functions
+ ****************************************************************************/
+
+static inline void set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
+{
+ dev->absmin[axis] = min;
+ dev->absmax[axis] = max;
+ dev->absfuzz[axis] = fuzz;
+ dev->absflat[axis] = flat;
+
+ set_bit(axis, dev->absbit);
+}
+
+static void lbtouch_disconnect(struct psmouse *psmouse)
+{
+ unsigned char param[1];
+
+ param[0] = 0x06;
+
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) ||
+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE) ||
+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE) ||
+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
+ printk(KERN_WARNING "lbtouch.c: Failed to restore touchscreen PS/2 emulation\n");
+}
+
+int lbtouch_init(struct psmouse *psmouse, int set_properties)
+{
+ unsigned char param[1];
+
+ if (psmouse->serio->type != SERIO_8042)
+ return 0;
+
+ param[0] = 0x07;
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) ||
+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE) ||
+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE) ||
+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) {
+ printk(KERN_ERR "lbtouch.c: Failed to enable touchscreen native mode\n");
+ return 0;
+ }
+
+ if (set_properties) {
+ set_bit(EV_ABS, psmouse->dev.evbit);
+ set_abs_params(&psmouse->dev, ABS_X, limits[0], limits[1], 0, 0);
+ set_abs_params(&psmouse->dev, ABS_Y, limits[2], limits[3], 0, 0);
+
+ set_bit(EV_KEY, psmouse->dev.evbit);
+ set_bit(BTN_TOUCH, psmouse->dev.keybit);
+
+ clear_bit(EV_REL, psmouse->dev.evbit);
+ clear_bit(REL_X, psmouse->dev.relbit);
+ clear_bit(REL_Y, psmouse->dev.relbit);
+
+ psmouse->protocol_handler = lbtouch_process_byte;
+ psmouse->disconnect = lbtouch_disconnect;
+
+ lbtouch_pt_create(psmouse);
+ }
+
+ return 1;
+}
===== drivers/input/mouse/lbtouch.h 1.0 vs 1.1 =====
--- /dev/null Fri Aug 30 18:31:37 2002
+++ 1.1/drivers/input/mouse/lbtouch.h Thu Apr 22 01:21:29 2004
@@ -0,0 +1,16 @@
+/*
+ * Fujistsu Lifebook PS/2 touchscreen driver header
+ *
+ * Copyright (c) 2004 Dmitry Torokhov <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef _LBTOUCH_H
+#define _LBTOUCH_H
+
+int lbtouch_init(struct psmouse *psmouse, int set_properties);
+
+#endif

2004-04-22 07:06:19

by Sau Dan Lee

[permalink] [raw]
Subject: Re: /dev/psaux-Interface

>>>>> "Dmitry" == Dmitry Torokhov <[email protected]> writes:

Dmitry> OK, here you go. It is the first cut. The driver creates
Dmitry> an absolute device for the touchscreen and a fake
Dmitry> pass-through port to for the pointing device which works
Dmitry> in relative mode. All fancy stuff can be done in userspace
Dmitry> via evdev.

I still haven't tried it. But upon first inspection, I found
something undesirable already.

+static void lbtouch_pass_pt_packet(struct serio *ptport, unsigned char *packet)
+{
+ struct psmouse *child = ptport->private;
+
+ if (child && child->state == PSMOUSE_ACTIVATED) {
+ serio_interrupt(ptport, packet[0], 0, NULL);
+ serio_interrupt(ptport, packet[1], 0, NULL);
+ serio_interrupt(ptport, packet[2], 0, NULL);
+ }
+}
+

So, you're imposing the policy that the packets must as 3-byte
packets? My experiences in writing my XFree86 driver is that some
bytes are sometimes dropped, for reasons I don't know. My driver
would attempt to resync, although not reliably because the packet
format in touch-screen mode does not provide a reliable
synchronization mechanism (such as parity, a special bit to mark the
end of a packet, etc.).

I don't know whether the dropping of bytes is specific to my machine,
or is common to all B142 models.


+static psmouse_ret_t lbtouch_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+ struct input_dev *dev = &psmouse->dev;
+ unsigned char *p = psmouse->packet;
+ int x, y, touch;
+
+ input_regs(dev, regs);
+
+ if (psmouse->pktcnt < 3)
+ return PSMOUSE_GOOD_DATA;
+

The same problem. You wait for a complete 3-byte packet before
emitting an event. What happens to dropped bytes?


And what happens to the timeout feature in my XFree86 driver? That
feature is the main reason I write my driver, because that's what I
want and couldn't find (in others' implementation of the touchscreen
driver). The feature could be either in a XFree86 driver, or a kernel
mouse driver. But I'm not going to write another XFree86 driver. The
feature is already there in my XFree86 driver, and I just want direct
byte-level communication to the PSAUX port. No 3-byte boundarys
imposed. No censoring of data in either direction. It's that simple.
What make that so difficult?



--
Sau Dan LEE ???u??(Big5) ~{@nJX6X~}(HZ)

E-mail: [email protected]
Home page: http://www.informatik.uni-freiburg.de/~danlee

2004-04-22 07:30:30

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: /dev/psaux-Interface

On Thursday 22 April 2004 02:06 am, Sau Dan Lee wrote:
> >>>>> "Dmitry" == Dmitry Torokhov <[email protected]> writes:
>
> Dmitry> OK, here you go. It is the first cut. The driver creates
> Dmitry> an absolute device for the touchscreen and a fake
> Dmitry> pass-through port to for the pointing device which works
> Dmitry> in relative mode. All fancy stuff can be done in userspace
> Dmitry> via evdev.
>
> I still haven't tried it. But upon first inspection, I found
> something undesirable already.
>
> +static void lbtouch_pass_pt_packet(struct serio *ptport, unsigned char *packet)
> +{
> + struct psmouse *child = ptport->private;
> +
> + if (child && child->state == PSMOUSE_ACTIVATED) {
> + serio_interrupt(ptport, packet[0], 0, NULL);
> + serio_interrupt(ptport, packet[1], 0, NULL);
> + serio_interrupt(ptport, packet[2], 0, NULL);
> + }
> +}
> +
>
> So, you're imposing the policy that the packets must as 3-byte
> packets?

Yes, this is my uderstanding of Lifebook protocol. It is incapable of anything
but bare PS/2 as far as the pointing device goes. If we ever get a spec we can
revisit it.

> My experiences in writing my XFree86 driver is that some
> bytes are sometimes dropped, for reasons I don't know. My driver
> would attempt to resync, although not reliably because the packet
> format in touch-screen mode does not provide a reliable
> synchronization mechanism (such as parity, a special bit to mark the
> end of a packet, etc.).
>

There is a timeout and synchronization attempt in psmosue_interrupt (parent
of this module) so you should be covered.

> I don't know whether the dropping of bytes is specific to my machine,
> or is common to all B142 models.
>
>
> +static psmouse_ret_t lbtouch_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
> +{
> + struct input_dev *dev = &psmouse->dev;
> + unsigned char *p = psmouse->packet;
> + int x, y, touch;
> +
> + input_regs(dev, regs);
> +
> + if (psmouse->pktcnt < 3)
> + return PSMOUSE_GOOD_DATA;
> +
>
> The same problem. You wait for a complete 3-byte packet before
> emitting an event. What happens to dropped bytes?
>

The packet is dropped when we wait for a byte for too long.

--
Dmitry