summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/moused/moused.8466
-rw-r--r--usr.sbin/moused/moused.c1930
2 files changed, 2074 insertions, 322 deletions
diff --git a/usr.sbin/moused/moused.8 b/usr.sbin/moused/moused.8
index 1115bab..992ca27 100644
--- a/usr.sbin/moused/moused.8
+++ b/usr.sbin/moused/moused.8
@@ -30,92 +30,476 @@
.\"
.\" $Id: moused.8,v 1.5 1997/07/27 23:10:33 wosch Exp $
.\"
-.Dd December 16, 1996
+.Dd December 3, 1997
.Dt MOUSED 8
.Os FreeBSD
.Sh NAME
.Nm moused
-.Nd pass mouse data to console driver
+.Nd pass mouse data to the console driver
.Sh SYNOPSIS
.Nm
-.Op Fl DRcdfs
-.Op Fl r Ar samplerate
+.Op Fl 3DPRcdfs
+.Op Fl F Ar rate
+.Op Fl r Ar resolution
.Op Fl S Ar baudrate
+.Op Fl C Ar threshold
+.Op Fl m Ar N=M
+.Op Fl z Ar target
+.Op Fl t Ar mousetype
.Fl p Ar port
-.Fl t Ar mousetype
+.Pp
+.Nm
+.Op Fl Pd
+.Fl p Ar port
+.Fl i Ar info
.Sh DESCRIPTION
-The mouse daemon listens to a serial port for mouse data,
-interprets the data and then passes ioctls to the console
-driver.
+The mouse daemon
+.Nm
+and the console driver work together to support
+mouse operation in the text console and user programs.
+They virtualize the mouse and provide user programs with mouse data
+in the standard format
+.Pq see Xr sysmouse 4 .
+.Pp
+The mouse daemon listens to the specified port for mouse data,
+interprets and then passes it via ioctls to the console driver.
+The mouse daemon
+reports translation movement, button press/release
+events and movement of the roller or the wheel if available.
+The roller/wheel movement is reported as ``Z'' axis movement.
+.Pp
+The console driver will display the mouse pointer on the screen
+and provide cut and paste functions if the mouse pointer is enabled
+in the virtual console via
+.Xr vidcontrol 4 .
+If
+.Xr sysmouse 4
+is opened by the user program, the console driver also passes the mouse
+data to the device so that the user program will see it.
+.Pp
+If the mouse daemon receives the signal
+.Dv SIGHUP ,
+it will reopen the mouse port and reinitializes itself. Useful if
+the mouse is attached/detached while the system is suspended.
.Pp
-The options are as follows:
+The following options are available:
.Bl -tag -width indent
+.It Fl 3
+Emulate the third (middle) button for 2-button mice. It is emulated
+by pressing the left and right physical buttons simultaneously.
+.It Fl C Ar threshold
+Set double click speed as the maximum interval in msec between button clicks.
+Without this option, the default value of 500 msec will be assumed.
+This option will have effect only on the cut and paste operations
+in the text mode console. The user program which is reading mouse data
+via
+.Xr sysmouse 4
+won't be affected.
.It Fl D
-Lower DTR on the serial port.
+Lower DTR on the serial port.
+This option is valid only if
+.Ar mousesystems
+is selected as the protocol type.
+The DTR line may need to be dropped for a 3-button mouse
+to operate in the
+.Ar mousesystems
+mode.
+.It Fl F Ar rate
+Set the report rate (reports/sec) of the device if supported.
+.It Fl P
+Do not start the Plug and Play COM device enumeration procedure
+when identifying the serial mouse.
+If this option is given together with the
+.Fl i
+option, the
+.Nm
+command won't be able to print userful information for the serial mouse.
.It Fl R
Lower RTS on the serial port.
+This option is valid only if
+.Ar mousesystems
+is selected as the protocol type by the
+.Fl t
+option below. It is often used with the
+.Fl D
+option above. Both RTS and DTR lines may need to be dropped for
+a 3-button mouse to operate in the
+.Ar mousesystems
+mode.
.It Fl S Ar baudrate
Select the baudrate for the serial port (1200 to 9600).
+Not all serial mice support this option.
.It Fl c
-Enable ChordMiddle option.
+Some mice report middle button down events
+as if the left and right buttons are pressed. This option handles this.
.It Fl d
Enable debugging messages.
.It Fl f
Do not become a daemon and instead run as a foreground process.
+Useful for testing and debugging.
+.It Fl i Ar info
+Print specified information and quit. Available pieces of
+information are:
+.Pp
+.Bl -tag -compact -width modelxxx
+.It Ar port
+Port (device file) name, i.e.
+.Pa /dev/cuaa0 ,
+.Pa /dev/mse0
+and
+.Pa /dev/psm0.
+.It Ar if
+Interface type: serial, bus, inport or ps/2.
+.It Ar type
+Protocol type. It is one of the types listed under the
+.Fl t
+option below or
+.Ar sysmouse
+if the driver supports the
+.Ar sysmouse
+data format standard.
+.It Ar model
+Mouse model. The
+.Nm
+command may not always be able to identify the model.
+.It Ar all
+All of the above items. Print port, interface, type and model in this order
+in one line.
+.El
+.Pp
+If the
+.Nm
+command cannot determine the requested information, it prints ``unknown''
+or ``generic''.
+.It Fl m Ar N=M
+Assign the physical button
+.Ar M
+to the logical button
+.Ar N.
+You may specify as many instances of this option as you like.
+More than one physical button may be assigned to a logical button at the
+same time. In this case the logical button will be down,
+if either of the assigned physical buttons is held down.
+Do not put space around `='.
.It Fl p Ar port
Use
.Ar port
-as the serial port to communicate with the mouse.
-.It Fl r
-Set the bit sample rate on devices that support it (in Dots Per Inch).
+to communicate with the mouse.
+.It Fl r Ar resolution
+Set the resolution of the device; in Dots Per Inch, or
+.Ar low ,
+.Ar medium-low ,
+.Ar medium-high
+or
+.Ar high .
+This option may not be supported by all the device.
.It Fl s
Select a baudrate of 9600 for the serial line.
-.It Fl t Ar mousetype
-Specify the type of mouse attached to the
-serial port. Valid mouse types are:
+Not all serial mice support this option.
+.It Fl t Ar type
+Specify the protocol type of mouse attached to the port. Valid types are
+listed below.
.Pp
+For the serial mouse:
.Bl -tag -compact -width mousesystemsxxx
-.It microsoft
-Microsoft mouse
-.It mousesystems
-Mouse systems Corp mouse
-.It mmseries
-MM Series mouse
-.It logitech
-Logitech mouse
-.It busmouse
-A bus mouse
-.It mouseman
-Logitech MouseMan and TrackMan
-.It ps/2
-PS/2 mouse
-.It mmhittab
-MM HitTablet
+.It Ar microsoft
+Microsoft serial mouse protocol. Most 2-button serial mice use this protocol.
+.It Ar intellimouse
+Microsoft IntelliMouse protocol. Genius NetMouse, ASCII Mie Mouse,
+Logitech MouseMan+ and FirstMouse+ use this protocol too.
+Other mice with a roller/wheel may be compatible with this protocol.
+.It Ar mousesystems
+MouseSystems 5-byte protocol. 3-button mice may use this protocol.
+.It Ar mmseries
+MM Series mouse protocol.
+.It Ar logitech
+Logitech mouse protocol. Note that this is for old Logitech models.
+.Ar mouseman
+or
+.Ar intellimouse
+should be specified for newer models.
+.It Ar mouseman
+Logitech MouseMan and TrackMan protocol. Some 3-button mice may be compatible
+with this protocol. Note that MouseMan+ and FirstMouse+ use
+.Ar intellimouse
+protocol rather than this one.
+.It Ar glidepoint
+ALPS GlidePoint protocol.
+.It Ar thinkingmouse
+Kensington ThinkingMouse protocol.
+.It Ar mmhittab
+Hitachi tablet protocol.
.El
+.Pp
+For the bus and InPort mouse:
+.Bl -tag -compact -width mousesystemsxxx
+.It Ar busmouse
+This is the only protocol type available for
+the bus and InPort mouse and should be specified for any bus mice
+and InPort mice, regardless of the brand.
+.El
+.Pp
+For the PS/2 mouse:
+.Bl -tag -compact -width mousesystemsxxx
+.It Ar ps/2
+This is the only protocol type available for the PS/2 mouse
+and should be specified for any PS/2 mice, regardless of the brand.
+.El
+.It Fl z Ar target
+Map Z axis (roller/wheel) movement to another axis or to virtual buttons.
+Valid
+.Ar target
+maybe:
+.Bl -tag -compact -width x__
+.It Ar x
+.It Ar y
+X or Y axis movement will be reported when the Z axis movement is detected.
+.It Ar N
+Report the virtual buttons
+.Ar N
+and
+.Ar N+1
+down events respectively when negative and positive Z axis movement
+is detected. There doesn't need to be physical buttons
+.Ar N
+and
+.Ar N+1 .
+Note that mapping to logical buttons is carried out after mapping
+from the Z axis movement to the virtual buttons is done.
+.El
+.El
+.Ss Configureing Mouse Daemon
+The first thing you need to know is the interface type
+of the mouse you are going to use.
+It can be determined by looking at the connector of the mouse.
+The serial mouse has a D-Sub female 9- or 25-pin connector.
+The bus and InPort mice have either a D-Sub male 9-pin connector
+or a round DIN 9-pin connector.
+The PS/2 mouse is equipped with a small, round DIN 6-pin connector.
+Some mice come with adapters with which the connector can
+be converted to another. If you are to use such an adapter,
+remember the connector at the very end of the mouse/adapter pair is
+what matters.
+.Pp
+The next thing to decide is a port to use for the given interface.
+For the bus, InPort and PS/2 mice, there is little choice:
+the bus and InPort mice always use
+.Pa /dev/mse0,
+and the PS/2 mouse is always at
+.Pa /dev/psm0.
+There may be more than one serial port to which the serial
+mouse can be attached. Many people often assign the first, built-in
+serial port
+.Pa /dev/cuaa0
+to the mouse.
+You may want to create a symbolic link
+.Pa /dev/mouse
+pointing to the real port to which the mouse is connected, so that you
+can easily distinguish which is your ``mouse'' port later.
+.Pp
+The next step is to guess the appropriate protocol type for the mouse.
+The
+.Nm
+command may be able to automatically determine the protocol type.
+Run the
+.Nm
+command with the
+.Fl i
+option and see what it says. If the command can identify
+the protocol type, no further investigation is necessary on your part.
+You may start the daemon without explicitly specifying a protocol type
+.Pq see Sx EXAMPLE .
+.Pp
+The command may print
+.Ar sysmouse
+if the mouse driver supports this protocol type.
+.Pp
+Note that the
+.Dv type
+and
+.Dv model
+printed by the
+.Fl i
+option do not necessarily match the product name of the pointing device
+in question, but they may give the name of the device with which it is
+compatible.
+.Pp
+If the
+.Fl i
+option yields nothing, you need to specify a protocol type to the
+.Nm
+command by the
+.Fl t
+option. You have to make a guess and try.
+There is rule of thumb:
+.Pp
+.Bl -tag -compact -width 1.X
+.It 1.
+The bus and InPort mice always use
+.Ar busmouse
+protocol regardless of the brand of the mouse.
+.It 2.
+The
+.Ar ps/2
+protocol should always be specified for the PS/2 mouse
+regardless of the brand of the mouse.
+.It 3.
+Most 2-button serial mice support the
+.Ar microsoft
+protocol.
+.It 4.
+3-button serial mice may work with the
+.Ar mousesystems
+protocol. If it doesn't, it may work with the
+.Ar microsoft
+protocol although
+the third (middle) button won't function.
+3-button serial mice may also work with the
+.Ar mouseman
+protocol under which the third button may function as expected.
+.It 5.
+3-button serial mice may have a small switch to choose between ``MS''
+and ``PC'', or ``2'' and ``3''.
+``MS'' or ``2'' usually mean the
+.Ar microsoft
+protocol.
+``PC'' or ``3'' will choose the
+.Ar mousesystems
+protocol.
+.It 6.
+If the mouse has a roller or a wheel, it may be compatible with the
+.Ar intellimouse
+protocol.
+.El
+.Pp
+To test if the selected protocol type is correct for the given mouse,
+enable the mouse pointer in the current virtual console,
+.Pp
+.Dl vidcontrol -m on
+.Pp
+start the mouse daemon in the foreground mode,
+.Pp
+.Dl moused -f -p Ar _selected_port_ -t Ar _selected_protocol_
+.Pp
+and see if the mouse pointer travels correctly
+according to the mouse movement. Then try cur & paste features by
+clicking the left, right and middle buttons. Type ^C to stop
+the command.
+.Ss Multiple Mice
+As many instances of the mouse daemon as the number of mice attached to
+the system may be run simultaneously; one
+instance for each mouse.
+This is useful if the user wants to use the built-in PS/2 pointing device
+of a laptop computer while on the road, but wants to use a serial
+mouse when s/he attaches the system to the docking station in the office.
+Run two mouse daemons and tell the application program
+.Pq such as the X Window System
+to use
+.Xr sysmouse ,
+then the application program will always see mouse data from either mice.
+When the serial mouse is not attached, the corresponding mouse daemon
+won't detect any movement or button state change and the application
+program will only see mouse data coming from the daemon for the
+PS/2 mouse. In contrast when both mice are attached and both of them
+are moved at the same time in this configuration,
+the mouse pointer will travel across the screen just as if movement of
+the mice is combined all together.
+.Sh FILES
+.Bl -tag -width /dev/consolectl -compact
+.It Pa /dev/consolectl
+device to control the console
+.It Pa /dev/mse%d
+bus and InPort mouse driver
+.It Pa /dev/psm%d
+PS/2 mouse driver
+.It Pa /dev/sysmouse
+virtualized mouse driver
+.It Pa /dev/ttyv%d
+virtual consoles
.El
.Sh EXAMPLE
.Pp
-.Dl moused -t microsoft -p /dev/mouse
+.Dl moused -p /dev/cuaa0 -i type
+.Pp
+Let the
+.Nm
+command determine the protocol type of the mouse at the serial port
+.Pa /dev/cuaa0.
+If successful, the command will print the type, otherwise it will say
+``unknown''.
+.Pp
+.Dl moused -p /dev/cuaa0
.Dl vidcontrol -m on
.Pp
-Start the mouse daemon on the serial device
-.Pa /dev/mouse
-for a microsoft mouse and enable the mousepointer.
+If the
+.Nm
+command is able to identify the protocol type of the mouse at the specified
+port automatically, you can start the daemon without the
+.Fl t
+option and enable the mouse pointer in the text console as above.
+.Pp
+.Dl moused -p /dev/mouse -t microsoft
+.Dl vidcontrol -m on
+.Pp
+Start the mouse daemon on the serial port
+.Pa /dev/mouse.
+The protocol type
+.Ar microsoft
+is explicitly specified by the
+.Fl t
+option.
+.Pp
+.Dl moused -p /dev/mouse -m 1=3 -m 3=1
+.Pp
+Assign the physical button 3 (right button) to the logical button 1
+(logical left) and the physical button 1 (left) to the logical
+button 3 (logical right).
+This will effectively swap the left and right buttons.
+.Pp
+.Dl moused -p /dev/mouse -t intellimouse -z 4
+.Pp
+Report negative Z axis (roller) movement as the button 4 pressed
+and positive Z axis movement as the button 5 pressed.
+.Sh CAVEATS
+The
+.Nm
+command does not currently work with the alternative console driver
+.Xr pcvt 4 .
+.Pp
+Many pad devices behave as if the first (left) button were pressed if
+the user `taps' the surface of the pad.
+In contrast, some ALPS GlidePoint pad models treat the tapping action
+as fourth button events. Use the option ``-m 1=4'' for these models
+to obtain the same effect as the other pad devices.
.Sh SEE ALSO
+.Xr kill 1 ,
.Xr vidcontrol 1 ,
.Xr keyboard 4 ,
+.Xr mse 4 ,
.Xr pcvt 4 ,
+.Xr psm 4 ,
.Xr screen 4 ,
.Xr sysmouse 4
+.Sh STANDARD
+The
+.Nm
+command partially supports ``Plag and Play External COM Device Specification''
+in order to support PnP serial mice.
+However, due to various degrees of conformance to the specification by
+existing serial mice, it does not strictly follow the version 1.0 of the
+standard. Even with this less strict approach,
+it may not always determine an appropriate protocol type
+for the given serial mouse.
.Sh AUTHORS
The
.Nm
command was written by
.An Michael Smith .
-
-This manual page
-was written by
-.An Mike Pritchard Aq mpp@FreeBSD.org .
+This manual page was written by
+.An Mike Pritchard Aq mpp@FreeBSD.org .
+The command and the manual page have been updated by
+.An Kazutaka YOKOTA Aq yokota@FreeBSD.org
+since.
.Sh HISTORY
The
.Nm
diff --git a/usr.sbin/moused/moused.c b/usr.sbin/moused/moused.c
index 5e4abda..6bd781f 100644
--- a/usr.sbin/moused/moused.c
+++ b/usr.sbin/moused/moused.c
@@ -34,8 +34,9 @@
/**
** MOUSED.C
**
- ** Mouse daemon : listens to serial port for mouse data stream,
- ** interprets same and passes ioctls off to the console driver.
+ ** Mouse daemon : listens to a serial port, the bus mouse interface, or
+ ** the PS/2 mouse port for mouse data stream, interprets data and passes
+ ** ioctls off to the console driver.
**
** The mouse interface functions are derived closely from the mouse
** handler in the XFree86 X server. Many thanks to the XFree86 people
@@ -45,7 +46,7 @@
#ifndef lint
static const char rcsid[] =
- "$Id$";
+ "$Id: moused.c,v 1.10 1997/09/25 06:44:39 charnier Exp $";
#endif /* not lint */
#include <err.h>
@@ -54,121 +55,387 @@ static const char rcsid[] =
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
+#include <ctype.h>
+#include <signal.h>
+#include <setjmp.h>
#include <termios.h>
+#include <syslog.h>
+
#include <machine/console.h>
+#include <machine/mouse.h>
+
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
+#define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */
+
+#define TRUE 1
+#define FALSE 0
+
+#define MOUSE_XAXIS (-1)
+#define MOUSE_YAXIS (-2)
+
+#define ChordMiddle 0x0001
+#define Emulate3Button 0x0002
+#define ClearDTR 0x0004
+#define ClearRTS 0x0008
+#define NoPnP 0x0010
+
+#define ID_NONE 0
+#define ID_PORT 1
+#define ID_IF 2
+#define ID_TYPE 4
+#define ID_MODEL 8
+#define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
+
#define debug(fmt,args...) \
if (debug&&nodaemon) warnx(fmt, ##args)
+#define logerr(e, fmt, args...) { \
+ if (background) { \
+ syslog(LOG_DAEMON | LOG_ERR, fmt ": %m", ##args); \
+ exit(e); \
+ } else \
+ err(e, fmt, ##args); \
+}
+
+#define logerrx(e, fmt, args...) { \
+ if (background) { \
+ syslog(LOG_DAEMON | LOG_ERR, fmt, ##args); \
+ exit(e); \
+ } else \
+ errx(e, fmt, ##args); \
+}
+
+#define logwarn(fmt, args...) { \
+ if (background) \
+ syslog(LOG_DAEMON | LOG_WARNING, fmt ": %m", ##args); \
+ else \
+ warn(fmt, ##args); \
+}
+
+#define logwarnx(fmt, args...) { \
+ if (background) \
+ syslog(LOG_DAEMON | LOG_WARNING, fmt, ##args); \
+ else \
+ warnx(fmt, ##args); \
+}
+
+/* structures */
+
+/* symbol table entry */
+typedef struct {
+ char *name;
+ int val;
+ int val2;
+} symtab_t;
+
+/* serial PnP ID string */
+typedef struct {
+ int revision; /* PnP revision, 100 for 1.00 */
+ char *eisaid; /* EISA ID including mfr ID and product ID */
+ char *serial; /* serial No, optional */
+ char *class; /* device class, optional */
+ char *compat; /* list of compatible drivers, optional */
+ char *description; /* product description, optional */
+ int neisaid; /* length of the above fields... */
+ int nserial;
+ int nclass;
+ int ncompat;
+ int ndescription;
+} pnpid_t;
+
+/* global variables */
+
int debug = 0;
-int nodaemon = 0;
-
-void usage(void);
-
-#define R_UNKNOWN 0
-#define R_MICROSOFT 1
-#define R_MOUSESYS 2
-#define R_MMSERIES 3
-#define R_LOGITECH 4
-#define R_BUSMOUSE 5
-#define R_LOGIMAN 6
-#define R_PS_2 7
-#define R_MMHITAB 8
-
-char *rnames[] = {
- "xxx",
+int nodaemon = FALSE;
+int background = FALSE;
+int identify = ID_NONE;
+int extioctl = FALSE;
+
+/* local variables */
+
+/* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
+static symtab_t rifs[] = {
+ { "serial", MOUSE_IF_SERIAL },
+ { "bus", MOUSE_IF_BUS },
+ { "inport", MOUSE_IF_INPORT },
+ { "ps/2", MOUSE_IF_PS2 },
+ { "sysmouse", MOUSE_IF_SYSMOUSE },
+ { NULL, MOUSE_IF_UNKNOWN },
+};
+
+/* types (the table must be ordered by MOUSE_PROTO_XXX in mouse.h) */
+static char *rnames[] = {
"microsoft",
"mousesystems",
- "mmseries",
"logitech",
- "busmouse",
+ "mmseries",
"mouseman",
+ "busmouse",
+ "inportmouse",
"ps/2",
"mmhitab",
+ "glidepoint",
+ "intellimouse",
+ "thinkingmouse",
+ "sysmouse",
+#if notyet
+ "mariqua",
+#endif
NULL
};
-unsigned short rodentcflags[] =
+/* models */
+static symtab_t rmodels[] = {
+ { "NetScroll", MOUSE_MODEL_NETSCROLL },
+ { "NetMouse", MOUSE_MODEL_NET },
+ { "GlidePoint", MOUSE_MODEL_GLIDEPOINT },
+ { "ThinkingMouse", MOUSE_MODEL_THINK },
+ { "IntelliMouse", MOUSE_MODEL_INTELLI },
+ { "EasyScroll", MOUSE_MODEL_EASYSCROLL },
+ { "MouseMan+", MOUSE_MODEL_MOUSEMANPLUS },
+ { "generic", MOUSE_MODEL_GENERIC },
+ { NULL, MOUSE_MODEL_UNKNOWN },
+};
+
+/* PnP EISA/product IDs */
+static symtab_t pnpprod[] = {
+ /* Kensignton ThinkingMouse */
+ { "KML0001", MOUSE_PROTO_THINK, MOUSE_MODEL_THINK },
+ /* MS IntelliMouse */
+ { "MSH0001", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI },
+ /* MS IntelliMouse TrackBall */
+ { "MSH0004", MOUSE_PROTO_INTELLI, MOUSE_MODEL_INTELLI },
+ /* Genius EZScroll */
+ { "KYEEZ00", MOUSE_PROTO_MS, MOUSE_MODEL_EASYSCROLL },
+ /* Genius NetMouse */
+ { "KYE0003", MOUSE_PROTO_INTELLI, MOUSE_MODEL_NET },
+ /* Logitech MouseMan+ */
+ { "LGI8050", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS },
+ /* Logitech FirstMouse+ */
+ { "LGI8051", MOUSE_PROTO_INTELLI, MOUSE_MODEL_MOUSEMANPLUS },
+
+ /* MS bus */
+ { "PNP0F00", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC },
+ /* MS serial */
+ { "PNP0F01", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
+ /* MS InPort */
+ { "PNP0F02", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC },
+ /* MS PS/2 */
+ { "PNP0F03", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC },
+ /*
+ * EzScroll returns PNP0F04 in the compatible device field; but it
+ * doesn't look compatible... XXX
+ */
+ /* MouseSystems */
+ { "PNP0F04", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC },
+ /* MouseSystems */
+ { "PNP0F05", MOUSE_PROTO_MSC, MOUSE_MODEL_GENERIC },
+#if notyet
+ /* Genius Mouse */
+ { "PNP0F06", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+ /* Genius Mouse */
+ { "PNP0F07", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+#endif
+ /* Logitech serial */
+ { "PNP0F08", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
+ /* MS BallPoint serial */
+ { "PNP0F09", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
+ /* MS PnP serial */
+ { "PNP0F0A", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
+ /* MS PnP BallPoint serial */
+ { "PNP0F0B", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
+ /* MS serial comatible */
+ { "PNP0F0C", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
+ /* MS InPort comatible */
+ { "PNP0F0D", MOUSE_PROTO_INPORT, MOUSE_MODEL_GENERIC },
+ /* MS PS/2 comatible */
+ { "PNP0F0E", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC },
+ /* MS BallPoint comatible */
+ { "PNP0F0F", MOUSE_PROTO_MS, MOUSE_MODEL_GENERIC },
+#if notyet
+ /* TI QuickPort */
+ { "PNP0F10", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+#endif
+ /* MS bus comatible */
+ { "PNP0F11", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC },
+ /* Logitech PS/2 */
+ { "PNP0F12", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC },
+ /* PS/2 */
+ { "PNP0F13", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC },
+#if notyet
+ /* MS Kids Mouse */
+ { "PNP0F14", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+#endif
+ /* Logitech bus */
+ { "PNP0F15", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC },
+#if notyet
+ /* Logitech SWIFT */
+ { "PNP0F16", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+#endif
+ /* Logitech serial compat */
+ { "PNP0F17", MOUSE_PROTO_LOGIMOUSEMAN, MOUSE_MODEL_GENERIC },
+ /* Logitech bus compatible */
+ { "PNP0F18", MOUSE_PROTO_BUS, MOUSE_MODEL_GENERIC },
+ /* Logitech PS/2 compatible */
+ { "PNP0F19", MOUSE_PROTO_PS2, MOUSE_MODEL_GENERIC },
+#if notyet
+ /* Logitech SWIFT compatible */
+ { "PNP0F1A", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+ /* HP Omnibook */
+ { "PNP0F1B", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+ /* Compaq LTE TrackBall PS/2 */
+ { "PNP0F1C", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+ /* Compaq LTE TrackBall serial */
+ { "PNP0F1D", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+ /* MS Kidts Trackball */
+ { "PNP0F1E", MOUSE_PROTO_???, MOUSE_MODEL_GENERIC },
+#endif
+
+ { NULL, MOUSE_PROTO_UNKNOWN, MOUSE_MODEL_GENERIC },
+};
+
+/* the table must be ordered by MOUSE_PROTO_XXX in mouse.h */
+static unsigned short rodentcflags[] =
{
- 0, /* nomouse */
(CS7 | CREAD | CLOCAL | HUPCL ), /* MicroSoft */
(CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* MouseSystems */
- (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ), /* MMSeries */
(CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* Logitech */
- 0, /* BusMouse */
+ (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ), /* MMSeries */
(CS7 | CREAD | CLOCAL | HUPCL ), /* MouseMan */
+ 0, /* Bus */
+ 0, /* InPort */
0, /* PS/2 */
- (CS8 | CREAD | CLOCAL | HUPCL ), /* MMHitTablet */
+ (CS8 | CREAD | CLOCAL | HUPCL ), /* MM HitTablet */
+ (CS7 | CREAD | CLOCAL | HUPCL ), /* GlidePoint */
+ (CS7 | CREAD | CLOCAL | HUPCL ), /* IntelliMouse */
+ (CS7 | CREAD | CLOCAL | HUPCL ), /* Thinking Mouse */
+ 0, /* sysmouse */
+#if notyet
+ (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* Mariqua */
+#endif
};
-
-typedef struct
-{
- int
- dx,dy,
- buttons;
-} ACTIVITY;
-
+static struct rodentparam {
+ int flags;
+ char *portname; /* /dev/XXX */
+ int rtype; /* MOUSE_PROTO_XXX */
+ int level; /* operation level: 0 or greater */
+ int baudrate;
+ int rate; /* report rate */
+ int resolution; /* MOUSE_RES_XXX or a positive number */
+ int zmap; /* MOUSE_{X|Y}AXIS or a button number */
+ int mfd; /* mouse file descriptor */
+ int cfd; /* /dev/consolectl file descriptor */
+ long clickthreshold; /* double click speed in msec */
+ mousehw_t hw; /* mouse device hardware information */
+ mousemode_t mode; /* protocol information */
+} rodent = {
+ flags : 0,
+ portname : NULL,
+ rtype : MOUSE_PROTO_UNKNOWN,
+ level : -1,
+ baudrate : 1200,
+ rate : 0,
+ resolution : MOUSE_RES_UNKNOWN,
+ zmap: 0,
+ mfd : -1,
+ cfd : -1,
+ clickthreshold : 500, /* 0.5 sec */
+};
-struct rodentparam
-{
- int
- baudrate,
- samplerate,
- flags,
- rtype,
- lastbuttons,
- buttons,
- mfd,
- cleardtr,
- clearrts;
-
- char
- *portname;
-
-} rodent = { baudrate : 1200,
- samplerate : 0,
- flags : 0,
- rtype : R_UNKNOWN,
- lastbuttons : 0,
- buttons : 0,
- mfd : -1,
- portname : NULL,
- cleardtr : 0,
- clearrts : 0};
-
-#define ChordMiddle 1
-
-void r_init(void);
-ACTIVITY *r_protocol(u_char b);
-void setmousespeed(int old, int new, unsigned cflag);
+/* button status */
+static struct {
+ int count; /* 0: up, 1: single click, 2: double click,... */
+ struct timeval tv; /* timestamp on the last `up' event */
+} buttonstate[MOUSE_MAXBUTTON];
+
+static jmp_buf env;
+
+/* function prototypes */
+
+static void moused(void);
+static void hup(int sig);
+static void usage(void);
+
+static int r_identify(void);
+static char *r_if(int type);
+static char *r_name(int type);
+static char *r_model(int model);
+static void r_init(void);
+static int r_protocol(u_char b, mousestatus_t *act);
+static int r_installmap(char *arg);
+static void r_map(mousestatus_t *act1, mousestatus_t *act2);
+static void r_click(mousestatus_t *act);
+static void setmousespeed(int old, int new, unsigned cflag);
+
+static int pnpgets(char *buf);
+static int pnpparse(pnpid_t *id, char *buf, int len);
+static symtab_t *pnpproto(pnpid_t *id);
+
+static symtab_t *gettoken(symtab_t *tab, char *s, int len);
+static char *gettokenname(symtab_t *tab, int val);
void
main(int argc, char *argv[])
{
- int c,i,cfd;
- u_char b;
- ACTIVITY *act;
- struct mouse_info mouse;
- fd_set fds;
-
- while((c = getopt(argc,argv,"cdfr:sp:t:h?RDS:")) != -1)
- switch(c)
- {
+ int c;
+ int i;
+
+ while((c = getopt(argc,argv,"3C:DF:PRS:cdfhi:l:m:p:r:st:z:")) != -1)
+ switch(c) {
+
+ case '3':
+ rodent.flags |= Emulate3Button;
+ break;
+
case 'c':
rodent.flags |= ChordMiddle;
break;
case 'd':
- debug = 1;
+ ++debug;
break;
case 'f':
- nodaemon = 1;
+ nodaemon = TRUE;
+ break;
+
+ case 'i':
+ if (strcmp(optarg, "all") == 0)
+ identify = ID_ALL;
+ else if (strcmp(optarg, "port") == 0)
+ identify = ID_PORT;
+ else if (strcmp(optarg, "if") == 0)
+ identify = ID_IF;
+ else if (strcmp(optarg, "type") == 0)
+ identify = ID_TYPE;
+ else if (strcmp(optarg, "model") == 0)
+ identify = ID_MODEL;
+ else {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ nodaemon = TRUE;
+ break;
+
+ case 'l':
+ rodent.level = atoi(optarg);
+ if ((rodent.level < 0) || (rodent.level > 4)) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ break;
+
+ case 'm':
+ if (!r_installmap(optarg)) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
break;
case 'p':
@@ -176,37 +443,95 @@ main(int argc, char *argv[])
break;
case 'r':
- rodent.samplerate = atoi(optarg);
+ if (strcmp(optarg, "high") == 0)
+ rodent.resolution = MOUSE_RES_HIGH;
+ else if (strcmp(optarg, "medium-high") == 0)
+ rodent.resolution = MOUSE_RES_HIGH;
+ else if (strcmp(optarg, "medium-low") == 0)
+ rodent.resolution = MOUSE_RES_MEDIUMLOW;
+ else if (strcmp(optarg, "low") == 0)
+ rodent.resolution = MOUSE_RES_LOW;
+ else if (strcmp(optarg, "default") == 0)
+ rodent.resolution = MOUSE_RES_DEFAULT;
+ else {
+ rodent.resolution = atoi(optarg);
+ if (rodent.resolution <= 0) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ }
break;
case 's':
rodent.baudrate = 9600;
break;
- case 'R':
- rodent.clearrts = 1;
+ case 'z':
+ if (strcmp(optarg, "x") == 0)
+ rodent.zmap = MOUSE_XAXIS;
+ else if (strcmp(optarg, "y") == 0)
+ rodent.zmap = MOUSE_YAXIS;
+ else {
+ i = atoi(optarg);
+ /*
+ * Use button i for negative Z axis movement and
+ * button (i + 1) for positive Z axis movement.
+ */
+ if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ rodent.zmap = 1 << (i - 1);
+ }
+ break;
+
+ case 'C':
+ rodent.clickthreshold = atoi(optarg);
+ if ((rodent.clickthreshold < 0) ||
+ (rodent.clickthreshold > MAX_CLICKTHRESHOLD)) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
break;
case 'D':
- rodent.cleardtr = 1;
+ rodent.flags |= ClearDTR;
+ break;
+
+ case 'F':
+ rodent.rate = atoi(optarg);
+ if (rodent.rate <= 0) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ break;
+
+ case 'P':
+ rodent.flags |= NoPnP;
+ break;
+
+ case 'R':
+ rodent.flags |= ClearRTS;
break;
case 'S':
rodent.baudrate = atoi(optarg);
+ if (rodent.baudrate <= 0) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
debug("rodent baudrate %d", rodent.baudrate);
break;
case 't':
for (i = 0; rnames[i]; i++)
- if (!strcmp(optarg,rnames[i]))
- {
- debug("rodent is %s",rnames[i]);
+ if (!strcmp(optarg,rnames[i])) {
rodent.rtype = i;
break;
}
if (rnames[i])
break;
- warnx("no such mouse type `%s'",optarg);
+ warnx("no such mouse type `%s'", optarg);
usage();
case 'h':
@@ -215,16 +540,23 @@ main(int argc, char *argv[])
usage();
}
- switch(rodent.rtype)
- {
- case R_BUSMOUSE:
+ /* the default port name */
+ switch(rodent.rtype) {
+
+ case MOUSE_PROTO_INPORT:
+ /* INPORT and BUS are the same... */
+ rodent.rtype = MOUSE_PROTO_BUS;
+ /* FALL THROUGH */
+ case MOUSE_PROTO_BUS:
if (!rodent.portname)
rodent.portname = "/dev/mse0";
break;
- case R_PS_2:
+
+ case MOUSE_PROTO_PS2:
if (!rodent.portname)
rodent.portname = "/dev/psm0";
break;
+
default:
if (rodent.portname)
break;
@@ -232,64 +564,177 @@ main(int argc, char *argv[])
usage();
}
- if ((rodent.mfd = open(rodent.portname, O_RDWR, 0)) == -1)
- {
- warn("can't open %s",rodent.portname);
- usage();
- }
- r_init(); /* call init function */
+ for (;;) {
+ if (setjmp(env) == 0) {
+ signal(SIGHUP, hup);
+ if ((rodent.mfd = open(rodent.portname, O_RDWR | O_NONBLOCK, 0))
+ == -1)
+ logerr(1, "unable to open %s", rodent.portname);
+ if (r_identify() == MOUSE_PROTO_UNKNOWN) {
+ logwarnx("cannot determine mouse type on %s", rodent.portname);
+ close(rodent.mfd);
+ rodent.mfd = -1;
+ }
- if ((cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
- err(1, "open(/dev/consolectl)");
+ /* print some information */
+ if (identify != ID_NONE) {
+ if (identify == ID_ALL)
+ printf("%s %s %s %s\n",
+ rodent.portname, r_if(rodent.hw.iftype),
+ r_name(rodent.rtype), r_model(rodent.hw.model));
+ else if (identify & ID_PORT)
+ printf("%s\n", rodent.portname);
+ else if (identify & ID_IF)
+ printf("%s\n", r_if(rodent.hw.iftype));
+ else if (identify & ID_TYPE)
+ printf("%s\n", r_name(rodent.rtype));
+ else if (identify & ID_MODEL)
+ printf("%s\n", r_model(rodent.hw.model));
+ exit(0);
+ } else {
+ debug("port: %s interface: %s type: %s model: %s",
+ rodent.portname, r_if(rodent.hw.iftype),
+ r_name(rodent.rtype), r_model(rodent.hw.model));
+ }
- if (!nodaemon)
- if (daemon(0,0))
- {
- err(1, "daemon() failed");
+ if (rodent.mfd == -1) {
+ /*
+ * We cannot continue because of error. Exit if the
+ * program has not become a daemon. Otherwise, block
+ * until the the user corrects the problem and issues SIGHUP.
+ */
+ if (!background)
+ exit(1);
+ sigpause(0);
+ }
+
+ r_init(); /* call init function */
+ moused();
}
- for(;;)
- {
- FD_ZERO(&fds);
- FD_SET(rodent.mfd,&fds);
- select(FD_SETSIZE,&fds,NULL,&fds,NULL);
- i = read(rodent.mfd,&b,1); /* get a byte */
- if (i != 1) /* read returned or error; goodbye */
- {
- debug("read returned %d : %s exiting",i,strerror(errno));
+ if (rodent.mfd != -1)
close(rodent.mfd);
- exit(1);
+ if (rodent.cfd != -1)
+ close(rodent.cfd);
+ rodent.mfd = rodent.cfd = -1;
+ }
+ /* NOT REACHED */
+
+ exit(0);
+}
+
+static void
+moused(void)
+{
+ struct mouse_info mouse;
+ mousestatus_t action; /* original mouse action */
+ mousestatus_t action2; /* mapped action */
+ fd_set fds;
+ u_char b;
+
+ if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
+ logerr(1, "cannot open /dev/consolectl", 0);
+
+ if (!nodaemon && !background)
+ if (daemon(0, 0)) {
+ logerr(1, "failed to become a daemon", 0);
+ } else {
+ background = TRUE;
}
- act = r_protocol(b); /* pass byte to handler */
- if (act) /* handler detected action */
- {
- mouse.operation = MOUSE_ACTION;
- mouse.u.data.x = act->dx;
- mouse.u.data.y = act->dy;
- mouse.u.data.buttons = act->buttons;
- ioctl(cfd, CONS_MOUSECTL, &mouse);
- debug("activity : buttons 0x%02x dx %d dy %d",
- act->buttons,act->dx,act->dy);
+
+ /* clear mouse data */
+ bzero(&action, sizeof(action));
+ bzero(&action2, sizeof(action2));
+ bzero(&buttonstate, sizeof(buttonstate));
+ bzero(&mouse, sizeof(mouse));
+
+ /* choose which ioctl command to use */
+ mouse.operation = MOUSE_MOTION_EVENT;
+ extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0);
+
+ /* process mouse data */
+ for (;;) {
+
+ FD_ZERO(&fds);
+ FD_SET(rodent.mfd, &fds);
+ if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
+ logwarn("failed to read from mouse", 0);
+
+ read(rodent.mfd, &b, 1);
+ if (r_protocol(b, &action)) { /* handler detected action */
+ r_map(&action, &action2);
+ debug("activity : buttons 0x%08x dx %d dy %d dz %d",
+ action2.button, action2.dx, action2.dy, action2.dz);
+
+ if (extioctl) {
+ r_click(&action2);
+ if (action2.flags & MOUSE_POSCHANGED) {
+ mouse.operation = MOUSE_MOTION_EVENT;
+ mouse.u.data.buttons = action2.button;
+ mouse.u.data.x = action2.dx;
+ mouse.u.data.y = action2.dy;
+ mouse.u.data.z = action2.dz;
+ if (debug < 2)
+ ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
+ }
+ } else {
+ mouse.operation = MOUSE_ACTION;
+ mouse.u.data.buttons = action2.button;
+ mouse.u.data.x = action2.dx;
+ mouse.u.data.y = action2.dy;
+ mouse.u.data.z = action2.dz;
+ if (debug < 2)
+ ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
+ }
+
+ /*
+ * If the Z axis movement is mapped to a imaginary physical
+ * button, we need to cook up a corresponding button `up' event
+ * after sending a button `down' event.
+ */
+ if ((rodent.zmap > 0) && (action.dz != 0)) {
+ action.obutton = action.button;
+ action.dx = action.dy = action.dz = 0;
+ r_map(&action, &action2);
+ debug("activity : buttons 0x%08x dx %d dy %d dz %d",
+ action2.button, action2.dx, action2.dy, action2.dz);
+
+ if (extioctl) {
+ r_click(&action2);
+ } else {
+ mouse.operation = MOUSE_ACTION;
+ mouse.u.data.buttons = action2.button;
+ mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
+ if (debug < 2)
+ ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
+ }
+ }
}
}
+ /* NOT REACHED */
}
+static void
+hup(int sig)
+{
+ longjmp(env, 1);
+}
/**
** usage
**
** Complain, and free the CPU for more worthy tasks
**/
-void
+static void
usage(void)
{
- fprintf(stderr, "%s\n%s\n",
- "usage: moused [-DRcdfs] [-r samplerate] [-S baudrate]",
- " -p <port> -t <mousetype>");
+ fprintf(stderr, "%s\n%s\n%s\n",
+ "usage: moused [-3DRcdfs] [-F rate] [-r resolution] [-S baudrate] [-C threshold]",
+ " [-m N=M] [-z N] [-t <mousetype>] -p <port>",
+ " moused [-d] -i -p <port>");
exit(1);
}
-
/**
** Mouse interface code, courtesy of XFree86 3.1.2.
**
@@ -331,10 +776,172 @@ usage(void)
*
*/
+/**
+ ** GlidePoint support from XFree86 3.2.
+ ** Derived from the module:
+ **/
+
+/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86_Mouse.c,v 3.19 1996/10/16 14:40:51 dawes Exp $ */
+/* $XConsortium: xf86_Mouse.c /main/10 1996/01/30 15:16:12 kaleb $ */
-void
+/* the following table must be ordered by MOUSE_PROTO_XXX in mouse.h */
+static unsigned char proto[][7] = {
+ /* hd_mask hd_id dp_mask dp_id bytes b4_mask b4_id */
+ { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MicroSoft */
+ { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* MouseSystems */
+ { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* Logitech */
+ { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MMSeries */
+ { 0x40, 0x40, 0x40, 0x00, 3, ~0x23, 0x00 }, /* MouseMan */
+ { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* Bus */
+ { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* InPort */
+ { 0xc0, 0x00, 0x00, 0x00, 3, 0x00, 0xff }, /* PS/2 mouse */
+ { 0xe0, 0x80, 0x80, 0x00, 3, 0x00, 0xff }, /* MM HitTablet */
+ { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* GlidePoint */
+ { 0x40, 0x40, 0x40, 0x00, 3, ~0x3f, 0x00 }, /* IntelliMouse */
+ { 0x40, 0x40, 0x40, 0x00, 3, ~0x33, 0x00 }, /* ThinkingMouse */
+ { 0xf8, 0x80, 0x00, 0x00, 5, 0x00, 0xff }, /* sysmouse */
+#if notyet
+ { 0xf8, 0x80, 0x00, 0x00, 5, ~0x2f, 0x10 }, /* Mariqua */
+#endif
+};
+static unsigned char cur_proto[7];
+
+static int
+r_identify(void)
+{
+ char pnpbuf[256]; /* PnP identifier string may be up to 256 bytes long */
+ pnpid_t pnpid;
+ symtab_t *t;
+ int level;
+ int len;
+
+ /* set the driver operation level, if applicable */
+ if (rodent.level < 0)
+ rodent.level = 1;
+ ioctl(rodent.mfd, MOUSE_SETLEVEL, &rodent.level);
+ rodent.level = (ioctl(rodent.mfd, MOUSE_GETLEVEL, &level) == 0) ? level : 0;
+
+ /*
+ * Interrogate the driver and get some intelligence on the device...
+ * The following ioctl functions are not always supported by device
+ * drivers. When the driver doesn't support them, we just trust the
+ * user to supply valid information.
+ */
+ rodent.hw.iftype = MOUSE_IF_UNKNOWN;
+ rodent.hw.model = MOUSE_MODEL_GENERIC;
+ ioctl(rodent.mfd, MOUSE_GETHWINFO, &rodent.hw);
+
+ if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
+ bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
+ rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
+ rodent.mode.rate = -1;
+ rodent.mode.resolution = MOUSE_RES_UNKNOWN;
+ rodent.mode.accelfactor = 0;
+ rodent.mode.level = 0;
+ if (ioctl(rodent.mfd, MOUSE_GETMODE, &rodent.mode) == 0) {
+ if ((rodent.mode.protocol == MOUSE_PROTO_UNKNOWN)
+ || (rodent.mode.protocol >= sizeof(proto)/sizeof(proto[0]))) {
+ logwarnx("unknown mouse protocol (%d)", rodent.mode.protocol);
+ return MOUSE_PROTO_UNKNOWN;
+ } else {
+ /* INPORT and BUS are the same... */
+ if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
+ rodent.mode.protocol = MOUSE_PROTO_BUS;
+ if (rodent.mode.protocol != rodent.rtype) {
+ /* Hmm, the driver doesn't agree with the user... */
+ if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
+ logwarnx("mouse type mismatch (%s != %s), %s is assumed",
+ r_name(rodent.mode.protocol), r_name(rodent.rtype),
+ r_name(rodent.mode.protocol));
+ rodent.rtype = rodent.mode.protocol;
+ bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
+ }
+ }
+ cur_proto[4] = rodent.mode.packetsize;
+ cur_proto[0] = rodent.mode.syncmask[0]; /* header byte bit mask */
+ cur_proto[1] = rodent.mode.syncmask[1]; /* header bit pattern */
+ }
+
+ /* maybe this is an PnP mouse... */
+ if (rodent.mode.protocol == MOUSE_PROTO_UNKNOWN) {
+
+ if (rodent.flags & NoPnP)
+ return rodent.rtype;
+ if (((len = pnpgets(pnpbuf)) <= 0) || !pnpparse(&pnpid, pnpbuf, len))
+ return rodent.rtype;
+
+ debug("PnP serial mouse: '%*.*s' '%*.*s' '%*.*s'",
+ pnpid.neisaid, pnpid.neisaid, pnpid.eisaid,
+ pnpid.ncompat, pnpid.ncompat, pnpid.compat,
+ pnpid.ndescription, pnpid.ndescription, pnpid.description);
+
+ /* we have a valid PnP serial device ID */
+ rodent.hw.iftype = MOUSE_IF_SERIAL;
+ t = pnpproto(&pnpid);
+ if (t != NULL) {
+ rodent.mode.protocol = t->val;
+ rodent.hw.model = t->val2;
+ } else {
+ rodent.mode.protocol = MOUSE_PROTO_UNKNOWN;
+ }
+ if (rodent.mode.protocol == MOUSE_PROTO_INPORT)
+ rodent.mode.protocol = MOUSE_PROTO_BUS;
+
+ /* make final adjustment */
+ if (rodent.mode.protocol != MOUSE_PROTO_UNKNOWN) {
+ if (rodent.mode.protocol != rodent.rtype) {
+ /* Hmm, the device doesn't agree with the user... */
+ if (rodent.rtype != MOUSE_PROTO_UNKNOWN)
+ logwarnx("mouse type mismatch (%s != %s), %s is assumed",
+ r_name(rodent.mode.protocol), r_name(rodent.rtype),
+ r_name(rodent.mode.protocol));
+ rodent.rtype = rodent.mode.protocol;
+ bcopy(proto[rodent.rtype], cur_proto, sizeof(cur_proto));
+ }
+ }
+ }
+
+ debug("proto params: %02x %02x %02x %02x %d %02x %02x",
+ cur_proto[0], cur_proto[1], cur_proto[2], cur_proto[3],
+ cur_proto[4], cur_proto[5], cur_proto[6]);
+
+ return rodent.rtype;
+}
+
+static char *
+r_if(int iftype)
+{
+ char *s;
+
+ s = gettokenname(rifs, iftype);
+ return (s == NULL) ? "unknown" : s;
+}
+
+static char *
+r_name(int type)
+{
+ return ((type == MOUSE_PROTO_UNKNOWN)
+ || (type > sizeof(rnames)/sizeof(rnames[0]) - 1))
+ ? "unknown" : rnames[type];
+}
+
+static char *
+r_model(int model)
+{
+ char *s;
+
+ s = gettokenname(rmodels, model);
+ return (s == NULL) ? "unknown" : s;
+}
+
+static void
r_init(void)
{
+ fd_set fds;
+ char *s;
+ char c;
+ int i;
+
/**
** This comment is a little out of context here, but it contains
** some useful information...
@@ -378,105 +985,191 @@ r_init(void)
** baud rates and sample rates. (The user will get an error.)
*/
-
- if (rodent.rtype == R_LOGIMAN)
- {
- setmousespeed(1200, 1200, rodentcflags[R_LOGIMAN]);
+ switch (rodent.rtype) {
+
+ case MOUSE_PROTO_LOGI:
+ /*
+ * The baud rate selection command must be sent at the current
+ * baud rate; try all likely settings
+ */
+ setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
+ setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
+ setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
+ setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
+ /* select MM series data format */
+ write(rodent.mfd, "S", 1);
+ setmousespeed(rodent.baudrate, rodent.baudrate,
+ rodentcflags[MOUSE_PROTO_MM]);
+ /* select report rate/frequency */
+ if (rodent.rate <= 0) write(rodent.mfd, "O", 1);
+ else if (rodent.rate <= 15) write(rodent.mfd, "J", 1);
+ else if (rodent.rate <= 27) write(rodent.mfd, "K", 1);
+ else if (rodent.rate <= 42) write(rodent.mfd, "L", 1);
+ else if (rodent.rate <= 60) write(rodent.mfd, "R", 1);
+ else if (rodent.rate <= 85) write(rodent.mfd, "M", 1);
+ else if (rodent.rate <= 125) write(rodent.mfd, "Q", 1);
+ else write(rodent.mfd, "N", 1);
+ break;
+
+ case MOUSE_PROTO_LOGIMOUSEMAN:
+ /* The command must always be sent at 1200 baud */
+ setmousespeed(1200, 1200, rodentcflags[rodent.rtype]);
write(rodent.mfd, "*X", 2);
- setmousespeed(1200, rodent.baudrate, rodentcflags[R_LOGIMAN]);
- } else {
- if ((rodent.rtype != R_BUSMOUSE) && (rodent.rtype != R_PS_2))
- {
- /* try all likely settings */
- setmousespeed(9600, rodent.baudrate, rodentcflags[rodent.rtype]);
- setmousespeed(4800, rodent.baudrate, rodentcflags[rodent.rtype]);
- setmousespeed(2400, rodent.baudrate, rodentcflags[rodent.rtype]);
- setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
-
- if (rodent.rtype == R_LOGITECH) {
- write(rodent.mfd, "S", 1);
- setmousespeed(rodent.baudrate, rodent.baudrate,
- rodentcflags[R_MMSERIES]);
- }
+ setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
+ break;
- if (rodent.rtype == R_MMHITAB) {
- char speedcmd;
- /*
- * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
- * The tablet must be configured to be in MM mode, NO parity,
- * Binary Format. xf86Info.sampleRate controls the sensativity
- * of the tablet. We only use this tablet for it's 4-button puck
- * so we don't run in "Absolute Mode"
- */
- write(rodent.mfd, "z8", 2); /* Set Parity = "NONE" */
- usleep(50000);
- write(rodent.mfd, "zb", 2); /* Set Format = "Binary" */
- usleep(50000);
- write(rodent.mfd, "@", 1); /* Set Report Mode = "Stream" */
- usleep(50000);
- write(rodent.mfd, "R", 1); /* Set Output Rate = "45 rps" */
- usleep(50000);
- write(rodent.mfd, "I\x20", 2); /* Set Incrememtal Mode "20" */
- usleep(50000);
- write(rodent.mfd, "E", 1); /* Set Data Type = "Relative */
- usleep(50000);
-
- /* These sample rates translate to 'lines per inch' on the
- Hitachi tablet */
- if (rodent.samplerate <= 40) speedcmd = 'g';
- else if (rodent.samplerate <= 100) speedcmd = 'd';
- else if (rodent.samplerate <= 200) speedcmd = 'e';
- else if (rodent.samplerate <= 500) speedcmd = 'h';
- else if (rodent.samplerate <= 1000) speedcmd = 'j';
- else speedcmd = 'd';
- write(rodent.mfd, &speedcmd, 1);
- usleep(50000);
-
- write(rodent.mfd, "\021", 1); /* Resume DATA output */
- } else {
- if (rodent.samplerate <= 0) write(rodent.mfd, "O", 1);
- else if (rodent.samplerate <= 15) write(rodent.mfd, "J", 1);
- else if (rodent.samplerate <= 27) write(rodent.mfd, "K", 1);
- else if (rodent.samplerate <= 42) write(rodent.mfd, "L", 1);
- else if (rodent.samplerate <= 60) write(rodent.mfd, "R", 1);
- else if (rodent.samplerate <= 85) write(rodent.mfd, "M", 1);
- else if (rodent.samplerate <= 125) write(rodent.mfd, "Q", 1);
- else write(rodent.mfd, "N", 1);
- }
+ case MOUSE_PROTO_HITTAB:
+ setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
+
+ /*
+ * Initialize Hitachi PUMA Plus - Model 1212E to desired settings.
+ * The tablet must be configured to be in MM mode, NO parity,
+ * Binary Format. xf86Info.sampleRate controls the sensativity
+ * of the tablet. We only use this tablet for it's 4-button puck
+ * so we don't run in "Absolute Mode"
+ */
+ write(rodent.mfd, "z8", 2); /* Set Parity = "NONE" */
+ usleep(50000);
+ write(rodent.mfd, "zb", 2); /* Set Format = "Binary" */
+ usleep(50000);
+ write(rodent.mfd, "@", 1); /* Set Report Mode = "Stream" */
+ usleep(50000);
+ write(rodent.mfd, "R", 1); /* Set Output Rate = "45 rps" */
+ usleep(50000);
+ write(rodent.mfd, "I\x20", 2); /* Set Incrememtal Mode "20" */
+ usleep(50000);
+ write(rodent.mfd, "E", 1); /* Set Data Type = "Relative */
+ usleep(50000);
+
+ /* Resolution is in 'lines per inch' on the Hitachi tablet */
+ if (rodent.resolution == MOUSE_RES_LOW) c = 'g';
+ else if (rodent.resolution == MOUSE_RES_MEDIUMLOW) c = 'e';
+ else if (rodent.resolution == MOUSE_RES_MEDIUMHIGH) c = 'h';
+ else if (rodent.resolution == MOUSE_RES_HIGH) c = 'd';
+ else if (rodent.resolution <= 40) c = 'g';
+ else if (rodent.resolution <= 100) c = 'd';
+ else if (rodent.resolution <= 200) c = 'e';
+ else if (rodent.resolution <= 500) c = 'h';
+ else if (rodent.resolution <= 1000) c = 'j';
+ else c = 'd';
+ write(rodent.mfd, &c, 1);
+ usleep(50000);
+
+ write(rodent.mfd, "\021", 1); /* Resume DATA output */
+ break;
+
+ case MOUSE_PROTO_THINK:
+ setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
+ /* the PnP ID string may be sent again, discard it */
+ usleep(200000);
+ i = FREAD;
+ ioctl(rodent.mfd, TIOCFLUSH, &i);
+ /* send the command to initialize the beast */
+ for (s = "E5E5"; *s; ++s) {
+ write(rodent.mfd, s, 1);
+ FD_ZERO(&fds);
+ FD_SET(rodent.mfd, &fds);
+ if (select(FD_SETSIZE, &fds, NULL, NULL, NULL) <= 0)
+ break;
+ read(rodent.mfd, &c, 1);
+ debug("%c", c);
+ if (c != *s)
+ break;
}
- }
- if (rodent.rtype == R_MOUSESYS && (rodent.cleardtr))
- {
- int val = TIOCM_DTR;
- ioctl(rodent.mfd, TIOCMBIC, &val);
- }
- if (rodent.rtype == R_MOUSESYS && (rodent.clearrts))
- {
- int val = TIOCM_RTS;
- ioctl(rodent.mfd, TIOCMBIC, &val);
+ break;
+
+ case MOUSE_PROTO_MSC:
+ setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
+ if (rodent.flags & ClearDTR) {
+ i = TIOCM_DTR;
+ ioctl(rodent.mfd, TIOCMBIC, &i);
+ }
+ if (rodent.flags & ClearRTS) {
+ i = TIOCM_RTS;
+ ioctl(rodent.mfd, TIOCMBIC, &i);
+ }
+ break;
+
+ case MOUSE_PROTO_BUS:
+ case MOUSE_PROTO_INPORT:
+ case MOUSE_PROTO_PS2:
+ case MOUSE_PROTO_SYSMOUSE:
+ if (rodent.rate >= 0)
+ rodent.mode.rate = rodent.rate;
+ if (rodent.resolution != MOUSE_RES_UNKNOWN)
+ rodent.mode.resolution = rodent.resolution;
+ ioctl(rodent.mfd, MOUSE_SETMODE, &rodent.mode);
+ break;
+
+ default:
+ setmousespeed(1200, rodent.baudrate, rodentcflags[rodent.rtype]);
+ break;
}
}
-ACTIVITY *
-r_protocol(u_char rBuf)
+static int
+r_protocol(u_char rBuf, mousestatus_t *act)
{
+ /* MOUSE_MSS_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
+ static int butmapmss[4] = { /* Microsoft, MouseMan, GlidePoint,
+ IntelliMouse, Thinking Mouse */
+ 0,
+ MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+ };
+ static int butmapmss2[4] = { /* Microsoft, MouseMan, GlidePoint,
+ Thinking Mouse */
+ 0,
+ MOUSE_BUTTON4DOWN,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
+ };
+ /* MOUSE_INTELLI_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
+ static int butmapintelli[4] = { /* IntelliMouse, NetMouse, Mie Mouse,
+ MouseMan+ */
+ 0,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON4DOWN,
+ MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN,
+ };
+ /* MOUSE_MSC_BUTTON?UP -> MOUSE_BUTTON?DOWN */
+ static int butmapmsc[8] = { /* MouseSystems, MMSeries, Logitech,
+ Bus, sysmouse */
+ 0,
+ MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
+ };
+ /* MOUSE_PS2_BUTTON?DOWN -> MOUSE_BUTTON?DOWN */
+ static int butmapps2[8] = { /* PS/2 */
+ 0,
+ MOUSE_BUTTON1DOWN,
+ MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
+ };
+ /* for Hitachi tablet */
+ static int butmaphit[8] = { /* MM HitTablet */
+ 0,
+ MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON1DOWN,
+ MOUSE_BUTTON4DOWN,
+ MOUSE_BUTTON5DOWN,
+ MOUSE_BUTTON6DOWN,
+ MOUSE_BUTTON7DOWN,
+ };
static int pBufP = 0;
static unsigned char pBuf[8];
- static ACTIVITY act;
-
- static unsigned char proto[10][5] = {
- /* hd_mask hd_id dp_mask dp_id nobytes */
- { 0, 0, 0, 0, 0 }, /* nomouse */
- { 0x40, 0x40, 0x40, 0x00, 3 }, /* MicroSoft */
- { 0xf8, 0x80, 0x00, 0x00, 5 }, /* MouseSystems */
- { 0xe0, 0x80, 0x80, 0x00, 3 }, /* MMSeries */
- { 0xe0, 0x80, 0x80, 0x00, 3 }, /* Logitech */
- { 0xf8, 0x80, 0x00, 0x00, 5 }, /* BusMouse */
- { 0x40, 0x40, 0x40, 0x00, 3 }, /* MouseMan */
- { 0xc0, 0x00, 0x00, 0x00, 3 }, /* PS/2 mouse */
- { 0xe0, 0x80, 0x80, 0x00, 3 }, /* MM_HitTablet */
- };
-
+
debug("received char 0x%x",(int)rBuf);
/*
@@ -501,15 +1194,17 @@ r_protocol(u_char rBuf)
* Microsoft...)
*/
- if (pBufP != 0 && rodent.rtype != R_PS_2 &&
- ((rBuf & proto[rodent.rtype][2]) != proto[rodent.rtype][3]
- || rBuf == 0x80))
+ if (pBufP != 0 && rodent.rtype != MOUSE_PROTO_PS2 &&
+ ((rBuf & cur_proto[2]) != cur_proto[3] || rBuf == 0x80))
{
pBufP = 0; /* skip package */
}
- if (pBufP == 0 &&
- (rBuf & proto[rodent.rtype][0]) != proto[rodent.rtype][1])
+ if (pBufP == 0 && (rBuf & cur_proto[0]) != cur_proto[1])
+ return 0;
+
+ /* is there an extra data byte? */
+ if (pBufP >= cur_proto[4] && (rBuf & cur_proto[0]) != cur_proto[1])
{
/*
* Hack for Logitech MouseMan Mouse - Middle button
@@ -527,81 +1222,403 @@ r_protocol(u_char rBuf)
* Even worse, different MouseMen and TrackMen differ in the 4th
* byte: some will send 0x00/0x20, others 0x01/0x21, or even
* 0x02/0x22, so I have to strip off the lower bits.
+ *
+ * [JCH-96/01/21]
+ * HACK for ALPS "fourth button". (It's bit 0x10 of the "fourth byte"
+ * and it is activated by tapping the glidepad with the finger! 8^)
+ * We map it to bit bit3, and the reverse map in xf86Events just has
+ * to be extended so that it is identified as Button 4. The lower
+ * half of the reverse-map may remain unchanged.
*/
- if ((rodent.rtype == R_MICROSOFT || rodent.rtype == R_LOGIMAN)
- && (char)(rBuf & ~0x23) == 0)
- {
- act.buttons = ((int)(rBuf & 0x20) >> 4)
- | (rodent.lastbuttons & 0x05);
- rodent.lastbuttons = act.buttons; /* save new button state */
- return(&act);
+
+ /*
+ * [KY-97/08/03]
+ * Receive the fourth byte only when preceeding three bytes have
+ * been detected (pBufP >= cur_proto[4]). In the previous
+ * versions, the test was pBufP == 0; thus, we may have mistakingly
+ * received a byte even if we didn't see anything preceeding
+ * the byte.
+ */
+
+ if ((rBuf & cur_proto[5]) != cur_proto[6]) {
+ pBufP = 0;
+ return 0;
+ }
+
+ switch (rodent.rtype) {
+#if notyet
+ case MOUSE_PROTO_MARIQUA:
+ /*
+ * This mouse has 16! buttons in addition to the standard
+ * three of them. They return 0x10 though 0x1f in the
+ * so-called `ten key' mode and 0x30 though 0x3f in the
+ * `function key' mode. As there are only 31 bits for
+ * button state (including the standard three), we ignore
+ * the bit 0x20 and don't distinguish the two modes.
+ */
+ act->dx = act->dy = act->dz = 0;
+ act->obutton = act->button;
+ rBuf &= 0x1f;
+ act->button = (1 << (rBuf - 13))
+ | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
+ /*
+ * FIXME: this is a button "down" event. There needs to be
+ * a corresponding button "up" event... XXX
+ */
+ break;
+#endif /* notyet */
+
+ /*
+ * IntelliMouse, NetMouse (including NetMouse Pro) and Mie Mouse
+ * always send the fourth byte, whereas the fourth byte is
+ * optional for GlidePoint and ThinkingMouse. The fourth byte
+ * is also optional for MouseMan+ and FirstMouse+ in their
+ * native mode. It is always sent if they are in the IntelliMouse
+ * compatible mode.
+ */
+ case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse,
+ MouseMan+ */
+ act->dx = act->dy = 0;
+ act->dz = (rBuf & 0x08) ? (rBuf & 0x0f) - 16 : (rBuf & 0x0f);
+ act->obutton = act->button;
+ act->button = butmapintelli[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
+ | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
+ break;
+
+ default:
+ act->dx = act->dy = act->dz = 0;
+ act->obutton = act->button;
+ act->button = butmapmss2[(rBuf & MOUSE_MSS_BUTTONS) >> 4]
+ | (act->obutton & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN));
+ break;
}
- return(NULL); /* skip package */
+ act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
+ | (act->obutton ^ act->button);
+ pBufP = 0;
+ return act->flags;
}
+ if (pBufP >= cur_proto[4])
+ pBufP = 0;
pBuf[pBufP++] = rBuf;
- if (pBufP != proto[rodent.rtype][4]) return(NULL);
+ if (pBufP != cur_proto[4])
+ return 0;
/*
* assembly full package
*/
- debug("assembled full packet (len %d) %x,%x,%x,%x,%x",
- proto[rodent.rtype][4], pBuf[0],pBuf[1],pBuf[2],pBuf[3],pBuf[4]);
+ debug("assembled full packet (len %d) %x,%x,%x,%x,%x,%x,%x,%x",
+ cur_proto[4],
+ pBuf[0], pBuf[1], pBuf[2], pBuf[3],
+ pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
- switch(rodent.rtype)
+ act->dz = 0;
+ act->obutton = act->button;
+ switch (rodent.rtype)
{
- case R_LOGIMAN: /* MouseMan / TrackMan */
- case R_MICROSOFT: /* Microsoft */
+ case MOUSE_PROTO_MS: /* Microsoft */
+ case MOUSE_PROTO_LOGIMOUSEMAN: /* MouseMan/TrackMan */
if (rodent.flags & ChordMiddle)
- act.buttons = (((int) pBuf[0] & 0x30) == 0x30) ? 2 :
- ((int)(pBuf[0]&0x20)>>3) | ((int)(pBuf[0]&0x10)>>4);
+ act->button = ((pBuf[0] & MOUSE_MSS_BUTTONS) == MOUSE_MSS_BUTTONS)
+ ? MOUSE_BUTTON2DOWN
+ : butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
else
- act.buttons = (rodent.lastbuttons & 2)
- | ((int)(pBuf[0] & 0x20) >> 3)
- | ((int)(pBuf[0] & 0x10) >> 4);
- act.dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
- act.dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
+ act->button = (act->obutton & MOUSE_BUTTON2DOWN)
+ | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
+ act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
+ act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
+ break;
+
+ case MOUSE_PROTO_GLIDEPOINT: /* GlidePoint */
+ case MOUSE_PROTO_THINK: /* ThinkingMouse */
+ case MOUSE_PROTO_INTELLI: /* IntelliMouse, NetMouse, Mie Mouse,
+ MouseMan+ */
+ act->button = (act->obutton & (MOUSE_BUTTON2DOWN | MOUSE_BUTTON4DOWN))
+ | butmapmss[(pBuf[0] & MOUSE_MSS_BUTTONS) >> 4];
+ act->dx = (char)(((pBuf[0] & 0x03) << 6) | (pBuf[1] & 0x3F));
+ act->dy = (char)(((pBuf[0] & 0x0C) << 4) | (pBuf[2] & 0x3F));
break;
- case R_MOUSESYS: /* Mouse Systems Corp */
- act.buttons = (~pBuf[0]) & 0x07;
- act.dx = (char)(pBuf[1]) + (char)(pBuf[3]);
- act.dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
+ case MOUSE_PROTO_MSC: /* MouseSystems Corp */
+#if notyet
+ case MOUSE_PROTO_MARIQUA: /* Mariqua */
+#endif
+ act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
+ act->dx = (char)(pBuf[1]) + (char)(pBuf[3]);
+ act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
break;
- case R_MMHITAB: /* MM_HitTablet */
- act.buttons = pBuf[0] & 0x07;
- if (act.buttons != 0)
- act.buttons = 1 << (act.buttons - 1);
- act.dx = (pBuf[0] & 0x10) ? pBuf[1] : - pBuf[1];
- act.dy = (pBuf[0] & 0x08) ? - pBuf[2] : pBuf[2];
+ case MOUSE_PROTO_HITTAB: /* MM HitTablet */
+ act->button = butmaphit[pBuf[0] & 0x07];
+ act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1];
+ act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2];
break;
- case R_MMSERIES: /* MM Series */
- case R_LOGITECH: /* Logitech Mice */
- act.buttons = pBuf[0] & 0x07;
- act.dx = (pBuf[0] & 0x10) ? pBuf[1] : - pBuf[1];
- act.dy = (pBuf[0] & 0x08) ? - pBuf[2] : pBuf[2];
+ case MOUSE_PROTO_MM: /* MM Series */
+ case MOUSE_PROTO_LOGI: /* Logitech Mice */
+ act->button = butmapmsc[pBuf[0] & MOUSE_MSC_BUTTONS];
+ act->dx = (pBuf[0] & MOUSE_MM_XPOSITIVE) ? pBuf[1] : - pBuf[1];
+ act->dy = (pBuf[0] & MOUSE_MM_YPOSITIVE) ? - pBuf[2] : pBuf[2];
break;
- case R_BUSMOUSE: /* BusMouse */
- act.buttons = (~pBuf[0]) & 0x07;
- act.dx = (char)pBuf[1];
- act.dy = - (char)pBuf[2];
+ case MOUSE_PROTO_BUS: /* Bus */
+ case MOUSE_PROTO_INPORT: /* InPort */
+ act->button = butmapmsc[(~pBuf[0]) & MOUSE_MSC_BUTTONS];
+ act->dx = (char)pBuf[1];
+ act->dy = - (char)pBuf[2];
break;
- case R_PS_2: /* PS/2 mouse */
- act.buttons = (pBuf[0] & 0x04) >> 1 | /* Middle */
- (pBuf[0] & 0x02) >> 1 | /* Right */
- (pBuf[0] & 0x01) << 2; /* Left */
- act.dx = (pBuf[0] & 0x10) ? pBuf[1]-256 : pBuf[1];
- act.dy = (pBuf[0] & 0x20) ? -(pBuf[2]-256) : -pBuf[2];
+ case MOUSE_PROTO_PS2: /* PS/2 */
+ act->button = butmapps2[pBuf[0] & MOUSE_PS2_BUTTONS];
+ act->dx = (pBuf[0] & MOUSE_PS2_XNEG) ? pBuf[1] - 256 : pBuf[1];
+ act->dy = (pBuf[0] & MOUSE_PS2_YNEG) ? -(pBuf[2] - 256) : -pBuf[2];
+ /*
+ * Moused usually operates the psm driver at the operation level 1
+ * which sends mouse data in MOUSE_PROTO_SYSMOUSE protocol.
+ * The following code takes effect only when the user explicitly
+ * requets the level 2 at which wheel movement and additional button
+ * actions are encoded in model-dependent formats. At the level 0
+ * the following code is no-op because the psm driver says the model
+ * is MOUSE_MODEL_GENERIC.
+ */
+ switch (rodent.hw.model) {
+ case MOUSE_MODEL_INTELLI:
+ case MOUSE_MODEL_NET:
+ /* wheel data is in the fourth byte */
+ act->dz = (char)pBuf[3];
+ break;
+ case MOUSE_MODEL_MOUSEMANPLUS:
+ if ((pBuf[0] & ~MOUSE_PS2_BUTTONS) == 0xc8) {
+ /* the extended data packet encodes button and wheel events */
+ act->dx = act->dy = 0;
+ act->dz = (pBuf[1] & MOUSE_PS2PLUS_ZNEG)
+ ? (pBuf[2] & 0x0f) - 16 : (pBuf[2] & 0x0f);
+ act->button |= ((pBuf[2] & MOUSE_PS2PLUS_BUTTON4DOWN)
+ ? MOUSE_BUTTON4DOWN : 0);
+ } else {
+ /* preserve button states */
+ act->button |= act->obutton & MOUSE_EXTBUTTONS;
+ }
+ break;
+ case MOUSE_MODEL_GLIDEPOINT:
+ /* `tapping' action */
+ act->button |= ((pBuf[0] & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN;
+ break;
+ case MOUSE_MODEL_NETSCROLL:
+ /* three addtional bytes encode button and wheel events */
+ act->button |= (pBuf[3] & MOUSE_PS2_BUTTON3DOWN)
+ ? MOUSE_BUTTON4DOWN : 0;
+ act->dz = (pBuf[3] & MOUSE_PS2_XNEG) ? pBuf[4] - 256 : pBuf[4];
+ break;
+ case MOUSE_MODEL_THINK:
+ /* the fourth button state in the first byte */
+ act->button |= (pBuf[0] & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0;
+ break;
+ case MOUSE_MODEL_GENERIC:
+ default:
+ break;
+ }
+ break;
+
+ case MOUSE_PROTO_SYSMOUSE: /* sysmouse */
+ act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
+ act->dx = (char)(pBuf[1]) + (char)(pBuf[3]);
+ act->dy = - ((char)(pBuf[2]) + (char)(pBuf[4]));
+ if (rodent.level == 1) {
+ act->dz = ((char)(pBuf[5] << 1) + (char)(pBuf[6] << 1))/2;
+ act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
+ }
break;
+
+ default:
+ return 0;
+ }
+ /*
+ * We don't reset pBufP here yet, as there may be an additional data
+ * byte in some protocols. See above.
+ */
+
+ /* has something changed? */
+ act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
+ | (act->obutton ^ act->button);
+
+ if (rodent.flags & Emulate3Button) {
+ if (((act->flags & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
+ == (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
+ && ((act->button & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
+ == (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))) {
+ act->button &= ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN);
+ act->button |= MOUSE_BUTTON2DOWN;
+ } else if ((act->obutton & MOUSE_BUTTON2DOWN)
+ && ((act->button & (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))
+ != (MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN))) {
+ act->button &= ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN
+ | MOUSE_BUTTON3DOWN);
+ }
+ act->flags &= MOUSE_POSCHANGED;
+ act->flags |= act->obutton ^ act->button;
+ }
+
+ return act->flags;
+}
+
+/* phisical to logical button mapping */
+static int p2l[MOUSE_MAXBUTTON] = {
+ MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
+ MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000,
+};
+
+static char *
+skipspace(char *s)
+{
+ while(isspace(*s))
+ ++s;
+ return s;
+}
+
+static int
+r_installmap(char *arg)
+{
+ int pbutton;
+ int lbutton;
+ char *s;
+
+ while (*arg) {
+ arg = skipspace(arg);
+ s = arg;
+ while (isdigit(*arg))
+ ++arg;
+ arg = skipspace(arg);
+ if ((arg <= s) || (*arg != '='))
+ return FALSE;
+ lbutton = atoi(s);
+
+ arg = skipspace(++arg);
+ s = arg;
+ while (isdigit(*arg))
+ ++arg;
+ if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
+ return FALSE;
+ pbutton = atoi(s);
+
+ if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
+ return FALSE;
+ if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
+ return FALSE;
+ p2l[pbutton - 1] = 1 << (lbutton - 1);
+ }
+
+ return TRUE;
+}
+
+static void
+r_map(mousestatus_t *act1, mousestatus_t *act2)
+{
+ register int pb;
+ register int pbuttons;
+ int lbuttons;
+
+ pbuttons = act1->button;
+ lbuttons = 0;
+
+ act2->obutton = act2->button;
+ act2->dx = act1->dx;
+ act2->dy = act1->dy;
+ act2->dz = act1->dz;
+
+ switch (rodent.zmap) {
+ case 0: /* do nothing */
+ break;
+ case MOUSE_XAXIS:
+ if (act1->dz != 0) {
+ act2->dx = act1->dz;
+ act2->dz = 0;
+ }
+ break;
+ case MOUSE_YAXIS:
+ if (act1->dz != 0) {
+ act2->dy = act1->dz;
+ act2->dz = 0;
+ }
+ break;
+ default: /* buttons */
+ pbuttons &= ~(rodent.zmap | (rodent.zmap << 1));
+ if (act1->dz < 0)
+ pbuttons |= rodent.zmap;
+ else if (act1->dz > 0)
+ pbuttons |= (rodent.zmap << 1);
+ act2->dz = 0;
+ break;
+ }
+
+ for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
+ lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
+ pbuttons >>= 1;
+ }
+ act2->button = lbuttons;
+
+ act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
+ | (act2->obutton ^ act2->button);
+}
+
+static void
+r_click(mousestatus_t *act)
+{
+ struct mouse_info mouse;
+ struct timeval tv;
+ struct timeval tv1;
+ struct timeval tv2;
+ struct timezone tz;
+ int button;
+ int mask;
+ int i;
+
+ mask = act->flags & MOUSE_BUTTONS;
+ if (mask == 0)
+ return;
+
+ gettimeofday(&tv1, &tz);
+ tv2.tv_sec = rodent.clickthreshold/1000;
+ tv2.tv_usec = (rodent.clickthreshold%1000)*1000;
+ timersub(&tv1, &tv2, &tv);
+ debug("tv: %ld %ld", tv.tv_sec, tv.tv_usec);
+ button = MOUSE_BUTTON1DOWN;
+ for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
+ if (mask & 1) {
+ if (act->button & button) {
+ /* the button is down */
+ debug(" : %ld %ld",
+ buttonstate[i].tv.tv_sec, buttonstate[i].tv.tv_usec);
+ if (timercmp(&tv, &buttonstate[i].tv, >)) {
+ buttonstate[i].tv.tv_sec = 0;
+ buttonstate[i].tv.tv_usec = 0;
+ buttonstate[i].count = 1;
+ } else {
+ ++buttonstate[i].count;
+ }
+ mouse.u.event.value = buttonstate[i].count;
+ } else {
+ /* the button is up */
+ buttonstate[i].tv = tv1;
+ mouse.u.event.value = 0;
+ }
+ mouse.operation = MOUSE_BUTTON_EVENT;
+ mouse.u.event.id = button;
+ if (debug < 2)
+ ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
+ debug("button %d count %d", i + 1, mouse.u.event.value);
+ }
+ button <<= 1;
+ mask >>= 1;
}
- pBufP = 0;
- return(&act);
}
/* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
@@ -631,18 +1648,16 @@ r_protocol(u_char rBuf)
*/
-void
-setmousespeed(old, new, cflag)
-int old;
-int new;
-unsigned cflag;
+static void
+setmousespeed(int old, int new, unsigned cflag)
{
struct termios tty;
char *c;
if (tcgetattr(rodent.mfd, &tty) < 0)
{
- err(1, "warning: unable to get status of mouse fd");
+ logwarn("unable to get status of mouse fd", 0);
+ return;
}
tty.c_iflag = IGNBRK | IGNPAR;
@@ -674,7 +1689,8 @@ unsigned cflag;
if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
{
- err(1, "unable to set status of mouse fd");
+ logwarn("unable to set status of mouse fd", 0);
+ return;
}
switch (new)
@@ -701,17 +1717,369 @@ unsigned cflag;
cfsetospeed(&tty, B1200);
}
- if (rodent.rtype == R_LOGIMAN || rodent.rtype == R_LOGITECH)
+ if (rodent.rtype == MOUSE_PROTO_LOGIMOUSEMAN
+ || rodent.rtype == MOUSE_PROTO_LOGI)
{
if (write(rodent.mfd, c, 2) != 2)
{
- err(1, "unable to write to mouse fd");
+ logwarn("unable to write to mouse fd", 0);
+ return;
}
}
usleep(100000);
if (tcsetattr(rodent.mfd, TCSADRAIN, &tty) < 0)
- {
- err(1,"unable to set status of mouse fd");
+ logwarn("unable to set status of mouse fd", 0);
+}
+
+/*
+ * PnP COM device support
+ *
+ * It's a simplistic implementation, but it works :-)
+ * KY, 31/7/97.
+ */
+
+/*
+ * Try to elicit a PnP ID as described in
+ * Microsoft, Hayes: "Plug and Play External COM Device Specification,
+ * rev 1.00", 1995.
+ *
+ * The routine does not fully implement the COM Enumerator as par Section
+ * 2.1 of the document. In particular, we don't have idle state in which
+ * the driver software monitors the com port for dynamic connection or
+ * removal of a device at the port, because `moused' simply quits if no
+ * device is found.
+ *
+ * In addition, as PnP COM device enumeration procedure slightly has
+ * changed since its first publication, devices which follow earlier
+ * revisions of the above spec. may fail to respond if the rev 1.0
+ * procedure is used. XXX
+ */
+static int
+pnpgets(char *buf)
+{
+ struct timeval timeout;
+ fd_set fds;
+ int i;
+ char c;
+
+#if 0
+ /*
+ * This is the procedure described in rev 1.0 of PnP COM device spec.
+ * Unfortunately, some devices which comform to earlier revisions of
+ * the spec gets confused and do not return the ID string...
+ */
+
+ /* port initialization (2.1.2) */
+ ioctl(rodent.mfd, TIOCMGET, &i);
+ i |= TIOCM_DTR; /* DTR = 1 */
+ i &= ~TIOCM_RTS; /* RTS = 0 */
+ ioctl(rodent.mfd, TIOCMSET, &i);
+ usleep(200000);
+ if ((ioctl(rodent.mfd, TIOCMGET, &i) == -1) || ((i & TIOCM_DSR) == 0))
+ goto disconnect_idle;
+
+ /* port setup, 1st phase (2.1.3) */
+ setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
+ i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
+ ioctl(rodent.mfd, TIOCMBIC, &i);
+ usleep(200000);
+ i = TIOCM_DTR; /* DTR = 1, RTS = 0 */
+ ioctl(rodent.mfd, TIOCMBIS, &i);
+ usleep(200000);
+
+ /* wait for response, 1st phase (2.1.4) */
+ i = FREAD;
+ ioctl(rodent.mfd, TIOCFLUSH, &i);
+ i = TIOCM_RTS; /* DTR = 1, RTS = 1 */
+ ioctl(rodent.mfd, TIOCMBIS, &i);
+
+ /* try to read something */
+ FD_ZERO(&fds);
+ FD_SET(rodent.mfd, &fds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 200000;
+ if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0) {
+
+ /* port setup, 2nd phase (2.1.5) */
+ i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
+ ioctl(rodent.mfd, TIOCMBIC, &i);
+ usleep(200000);
+
+ /* wait for respose, 2nd phase (2.1.6) */
+ i = FREAD;
+ ioctl(rodent.mfd, TIOCFLUSH, &i);
+ i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
+ ioctl(rodent.mfd, TIOCMBIS, &i);
+
+ /* try to read something */
+ FD_ZERO(&fds);
+ FD_SET(rodent.mfd, &fds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 200000;
+ if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
+ goto connect_idle;
+ }
+#else
+ /*
+ * This is a simplified procedure; it simply toggles RTS.
+ */
+
+ ioctl(rodent.mfd, TIOCMGET, &i);
+ i |= TIOCM_DTR; /* DTR = 1 */
+ i &= ~TIOCM_RTS; /* RTS = 0 */
+ ioctl(rodent.mfd, TIOCMSET, &i);
+ usleep(200000);
+
+ setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
+
+ /* wait for respose */
+ i = FREAD;
+ ioctl(rodent.mfd, TIOCFLUSH, &i);
+ i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
+ ioctl(rodent.mfd, TIOCMBIS, &i);
+
+ /* try to read something */
+ FD_ZERO(&fds);
+ FD_SET(rodent.mfd, &fds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 200000;
+ if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
+ goto connect_idle;
+#endif
+
+ /* collect PnP COM device ID (2.1.7) */
+ i = 0;
+ usleep(200000); /* the mouse must send `Begin ID' within 200msec */
+ while (read(rodent.mfd, &c, 1) == 1) {
+ /* we may see "M", or "M3..." before `Begin ID' */
+ if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
+ buf[i++] = c;
+ break;
+ }
+ debug("%c %02x", c, c);
+ }
+ if (i <= 0) {
+ /* we haven't seen `Begin ID' in time... */
+ goto connect_idle;
+ }
+
+ ++c; /* make it `End ID' */
+ for (;;) {
+ FD_ZERO(&fds);
+ FD_SET(rodent.mfd, &fds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 200000;
+ if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) <= 0)
+ break;
+
+ read(rodent.mfd, &buf[i], 1);
+ if (buf[i++] == c) /* End ID */
+ break;
+ if (i >= 256)
+ break;
+ }
+ /* string may not be human readable... */
+ debug("'%-*.*s'", i, i, buf);
+ if (buf[i - 1] != c)
+ goto connect_idle;
+ return i;
+
+ /*
+ * According to PnP spec, we should set DTR = 1 and RTS = 0 while
+ * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
+ * assuming there is something at the port even if it didn't
+ * respond to the PnP enumeration procedure.
+ */
+disconnect_idle:
+ i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
+ ioctl(rodent.mfd, TIOCMBIS, &i);
+connect_idle:
+ return 0;
+}
+
+static int
+pnpparse(pnpid_t *id, char *buf, int len)
+{
+ char s[3];
+ int offset;
+ int sum = 0;
+ int i, j;
+
+ id->revision = 0;
+ id->eisaid = NULL;
+ id->serial = NULL;
+ id->class = NULL;
+ id->compat = NULL;
+ id->description = NULL;
+ id->neisaid = 0;
+ id->nserial = 0;
+ id->nclass = 0;
+ id->ncompat = 0;
+ id->ndescription = 0;
+
+ offset = 0x28 - buf[0];
+
+ /* calculate checksum */
+ for (i = 0; i < len - 3; ++i) {
+ sum += buf[i];
+ buf[i] += offset;
+ }
+ sum += buf[len - 1];
+ for (; i < len; ++i)
+ buf[i] += offset;
+ debug("PnP ID string: '%*.*s'", len, len, buf);
+
+ /* revision */
+ buf[1] -= offset;
+ buf[2] -= offset;
+ id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
+ debug("PnP rev %d.%02d", id->revision / 100, id->revision % 100);
+
+ /* EISA vender and product ID */
+ id->eisaid = &buf[3];
+ id->neisaid = 7;
+
+ /* option strings */
+ i = 10;
+ if (buf[i] == '\\') {
+ /* device serial # */
+ for (j = ++i; i < len; ++i) {
+ if (buf[i] == '\\')
+ break;
+ }
+ if (i >= len)
+ i -= 3;
+ if (i - j == 8) {
+ id->serial = &buf[j];
+ id->nserial = 8;
}
+ }
+ if (buf[i] == '\\') {
+ /* PnP class */
+ for (j = ++i; i < len; ++i) {
+ if (buf[i] == '\\')
+ break;
+ }
+ if (i >= len)
+ i -= 3;
+ if (i > j + 1) {
+ id->class = &buf[j];
+ id->nclass = i - j;
+ }
+ }
+ if (buf[i] == '\\') {
+ /* compatible driver */
+ for (j = ++i; i < len; ++i) {
+ if (buf[i] == '\\')
+ break;
+ }
+ /*
+ * PnP COM spec prior to v0.96 allowed '*' in this field,
+ * it's not allowed now; just igore it.
+ */
+ if (buf[j] == '*')
+ ++j;
+ if (i >= len)
+ i -= 3;
+ if (i > j + 1) {
+ id->compat = &buf[j];
+ id->ncompat = i - j;
+ }
+ }
+ if (buf[i] == '\\') {
+ /* product description */
+ for (j = ++i; i < len; ++i) {
+ if (buf[i] == ';')
+ break;
+ }
+ if (i >= len)
+ i -= 3;
+ if (i > j + 1) {
+ id->description = &buf[j];
+ id->ndescription = i - j;
+ }
+ }
+
+ /* checksum exists if there are any optional fields */
+ if ((id->nserial > 0) || (id->nclass > 0)
+ || (id->ncompat > 0) || (id->ndescription > 0)) {
+ debug("PnP checksum: 0x%X", sum);
+ sprintf(s, "%02X", sum & 0x0ff);
+ if (strncmp(s, &buf[len - 3], 2) != 0) {
+#if 0
+ /*
+ * I found some mice do not comply with the PnP COM device
+ * spec regarding checksum... XXX
+ */
+ logwarnx("PnP checksum error", 0);
+ return FALSE;
+#endif
+ }
+ }
+
+ return TRUE;
+}
+
+static symtab_t *
+pnpproto(pnpid_t *id)
+{
+ symtab_t *t;
+ int i, j;
+
+ if (id->nclass > 0)
+ if (strncmp(id->class, "MOUSE", id->nclass) != 0)
+ /* this is not a mouse! */
+ return NULL;
+
+ if (id->neisaid > 0) {
+ t = gettoken(pnpprod, id->eisaid, id->neisaid);
+ if (t->val != MOUSE_PROTO_UNKNOWN)
+ return t;
+ }
+
+ /*
+ * The 'Compatible drivers' field may contain more than one
+ * ID separated by ','.
+ */
+ if (id->ncompat <= 0)
+ return NULL;
+ for (i = 0; i < id->ncompat; ++i) {
+ for (j = i; id->compat[i] != ','; ++i)
+ if (i >= id->ncompat)
+ break;
+ if (i > j) {
+ t = gettoken(pnpprod, id->compat + j, i - j);
+ if (t->val != MOUSE_PROTO_UNKNOWN)
+ return t;
+ }
+ }
+
+ return NULL;
+}
+
+/* name/val mapping */
+
+static symtab_t *
+gettoken(symtab_t *tab, char *s, int len)
+{
+ int i;
+
+ for (i = 0; tab[i].name != NULL; ++i) {
+ if (strncmp(tab[i].name, s, len) == 0)
+ break;
+ }
+ return &tab[i];
+}
+
+static char *
+gettokenname(symtab_t *tab, int val)
+{
+ int i;
+
+ for (i = 0; tab[i].name != NULL; ++i) {
+ if (tab[i].val == val)
+ return tab[i].name;
+ }
+ return NULL;
}
OpenPOWER on IntegriCloud