mdetect/0000755000000000000000000000000011227522331007367 5ustar mdetect/mdetect.c0000644000000000000000000002606211227510747011176 0ustar #include #include #include #include #include #include #include #include #include #include #include #include #include "mdetect.h" void really_giveup(int signum); static void usage(int); static struct device * stage1(struct device *); static void stage2(struct device *); static int handle_device(struct device *, fd_set *, unsigned long); static struct device * open_devices(void); static struct device * open_device(const char *name); static void restore_serial_settings(int code, void *data); static int opt_repeater = 0; int opt_verbose = 0; int opt_nopnp = 0; int opt_xf86config = 0; int xf86format = 0; static fd_set mouse_set; int main(int argc, char **argv) { struct device *dev, *tmp, *found; int c; while ((c = getopt(argc, argv, "hnorvx")) != -1) { switch (c) { case 'v': opt_verbose++; break; case 'r': opt_repeater = 1; break; case 'n': opt_nopnp = 1; break; case 'o': xf86format = 3; opt_xf86config = 1; break; case 'x': xf86format = 4; opt_xf86config = 1; break; case 'h': usage(0); default: usage(1); } } /* set up signal handler */ if (signal(SIGALRM, really_giveup) == SIG_ERR) { fprintf(stderr, "mdetect: can't set up signal handler!\n"); exit(3); } alarm(5); /* don't try to find a mouse for more than a few seconds */ if (opt_verbose) printf("The mouse police never sleep.\n"); if (!(dev = open_devices())) return 1; if (opt_verbose) { printf("Found the following devices:\n"); for (tmp = dev; tmp; tmp = tmp->next) printf(" %s\n", tmp->name); } /* Register a fucntion to restore all serial port settings on any * still open ports. */ on_exit(restore_serial_settings, (void *)dev); /* Now listen on all devices */ found = stage1(dev); if (found) stage2(found); while (dev) { if (dev->fd >= 0) { tcflush(dev->fd, TCIOFLUSH); if (dev->flags & DEV_SERIAL_PORT) tcsetattr(dev->fd, TCSAFLUSH, &dev->tty); close(dev->fd); dev->fd = -1; } dev = dev->next; } return found ? 0 : 1; } /* Normally this is called once if mdetect's overall 5 second timer expires. * When that happens, it sets another alarm for 1 second, and calls exit(2). * exit(2) will call restore_serial_settings(), previously registered via * on_exit(), and exit. The 1 second timer is to catch any hangs in the * exit() call, and if that expires we call _exit(2) bypassing the on_exit() * stuff. */ void really_giveup(int signum) { static int abort_now = 0; if (abort_now) _exit(2); else { /* set up signal handler again in case it was reset to SIG_DFL */ if (signal(SIGALRM, really_giveup) == SIG_ERR) { fprintf(stderr, "mdetect: can't set up signal handler second time\n"); _exit(2); } abort_now = 1; alarm(1); exit(2); } } static void restore_serial_settings(int code, void *data) { struct device *dev = (struct device *)data; while (dev) { if (dev->fd >= 0) { if (dev->flags & DEV_SERIAL_PORT) tcsetattr(dev->fd, TCSANOW, &dev->tty); close(dev->fd); } dev = dev->next; } } static void usage(int exitval) { fprintf(stderr, "Usage: mdetect [-hnrvox]\n"); fprintf(stderr, "\t-h\tdisplay this help message and exit\n" "\t-n\tdo not search for PnP (Plug 'n' Play) mice\n" "\t-r\t[not yet implemented]\n" "\t-v\tbe verbose; re-use for increasing verbosity\n" "\t-o\tproduce output appropriate for XFree86 3.x configuration\n" "\t-x\tproduce output appropriate for XFree86 4.x configuration\n"); exit(exitval); } static struct device * stage1(struct device *dev) { struct device *tmp; unsigned long timeout; struct timeval then; fd_set set; int max = -1; FD_ZERO(&mouse_set); FD_ZERO(&set); for (tmp = dev; tmp; tmp = tmp->next) { FD_SET(tmp->fd, &mouse_set); if (max < tmp->fd) max = tmp->fd; } /* Initialize time-keeping */ gettimeofday(&then, NULL); while (1) { struct timeval now, delta, tv, *tvp = NULL; unsigned long elapsed; gettimeofday(&now, NULL); timersub(&now, &then, &delta); elapsed = delta.tv_sec * 1000 + delta.tv_usec / 1000; timeout = 0; for (tmp = dev; tmp; tmp = tmp->next) { handle_device(tmp, &set, elapsed); if (timeout == 0 || tmp->timeout < timeout) timeout = tmp->timeout; if (tmp->flags & DEV_DRIVER_FOUND) return tmp; } memcpy(&set, &mouse_set, sizeof(mouse_set)); if (timeout) { tv.tv_sec = 0; tv.tv_usec = timeout * 1000; tvp = &tv; } then = now; if (select(max + 1, &set, NULL, NULL, tvp) < 0) { perror("select"); exit(1); } } return NULL; } static void stage2(struct device *dev) { struct mouse *driver = dev->driver; const char *name; unsigned char c; name = driver->name; if (driver->report) name = driver->report(driver); if (!opt_xf86config) { if (opt_verbose) { printf("\nDetected %s mouse on %s\n", driver->name, dev->name); fflush(stdout); } else { printf("%s\n%s\n", dev->name, driver->name); fflush(stdout); } } else { /* nasty, nasty special case logic for XFree86 */ if ((strcmp(dev->name, "/dev/psaux") == 0) || (strcmp(dev->name, "/dev/misc/psaux") == 0) #ifdef DEV_PSAUX_PREFIX || (strncmp(dev->name, "/dev/" DEV_PSAUX_PREFIX, sizeof("/dev/" DEV_PSAUX_PREFIX) - 1) == 0) #endif ) { if (strcasecmp(driver->xfree86_protocol_name, "IntelliMouse") == 0) { driver->xfree86_protocol_name = "ImPS/2"; } } if (opt_verbose) { switch (xf86format) { case 3: printf("Section \"Pointer\"\n"); printf("\tProtocol\t\"%s\"\n", driver->xfree86_protocol_name); printf("\tDevice\t\t\"%s\"\n", dev->name); printf("EndSection\n"); break; case 4: printf("Section \"InputDevice\"\n"); printf("\tIdentifier\t\"Generic Mouse\"\n"); printf("\tDriver\t\t\"mouse\"\n"); printf("\tOption\t\t\"CorePointer\"\n"); printf("\tOption\t\t\"Protocol\"\t\"%s\"\n", driver->xfree86_protocol_name); printf("\tOption\t\t\"Device\"\t\"%s\"\n", dev->name); printf("EndSection\n"); break; default: fprintf(stderr, "Unknown XF86Config output format!\n"); break; } } else { printf("%s\n%s\n", dev->name, driver->xfree86_protocol_name); } fflush(stdout); } /* Repeater code not yet complete */ if (opt_repeater) { while (1) { if (read(dev->fd, &c, 1) >= 0) driver->packet(dev, driver, c); } } } static int handle_device(struct device *dev, fd_set *set, unsigned long elapsed) { struct mouse *driver = dev->driver; if (dev->fd >= 0 && FD_ISSET(dev->fd, set)) { unsigned char c; dev->timeout = 0; if (read(dev->fd, &c, 1) < 0) goto bad; if (opt_verbose > 2) printf(" %-12s read 0x%02x\n", dev->name, c); if (driver->packet(dev, driver, c) < 0) goto bad; } else if (dev->timeout) { if (opt_verbose) printf(" %-12s timeout\n", dev->name); if (elapsed > dev->timeout) { if (!driver->timeout || driver->timeout(dev) < 0) goto bad; } dev->timeout = 0; } if (driver->good > MIN_GOOD_EVENTS) dev->flags |= DEV_DRIVER_FOUND; return 0; bad: if (opt_verbose) printf("\nClosing garbage device %s.\n", dev->name); FD_CLR(dev->fd, &mouse_set); if (dev->flags & DEV_SERIAL_PORT) tcsetattr(dev->fd, TCSAFLUSH, &dev->tty); close(dev->fd); dev->fd = -1; dev->timeout = 0; return -1; } /* * Send an event */ int send_event(struct mouse *driver) { static struct mouse *last = NULL; int ddx, ddy; #if 0 if (last != driver && opt_verbose) printf("\n"); #endif last = driver; if ((ddx = driver->lx - driver->dx) < 0) ddx = -ddx; if ((ddy = driver->ly - driver->dy) < 0) ddy = -ddy; if (opt_verbose) { unsigned int b =driver->buttons; printf("%3d %-12s %c%c%c %4d %4d %4d (der %3d) %3d%% \r", driver->total, driver->name, (b & BUTTON_LEFT)? 'L' : ' ', (b & BUTTON_MIDDLE)? 'M' : ' ', (b & BUTTON_RIGHT)? 'R' : ' ', driver->dx, driver->dy, driver->dz, ddx + ddy, 100 * driver->good / MIN_GOOD_EVENTS); fflush(stdout); if (opt_verbose > 1) printf("\n"); } driver->lx = driver->dx; driver->ly = driver->dy; driver->lz = driver->dz; /* Consistency checks for the first 20 events. * Note that the button check is the most effective one. * Motion values aren't that far off most of the time, * but buttons frequently are. * XXX: Tue Jun 22 11:12:25 MET DST 1999 * I disabled motion checks. All they effected was requiring * the user to move the mouse `slowly' according to various * reports. * * Without motion checks, mdetect still seems to work reliably, * plus you can jerk the mouse as much as you please. * --okir */ if (driver->good < MIN_GOOD_EVENTS) { if ((driver->buttons & (BUTTON_MIDDLE|BUTTON_RIGHT)) #if 0 || ddx > 30 || (driver->dx < -200 || driver->dx > 200) || (driver->dy < -200 || driver->dy > 200) #endif ) { if (opt_verbose) printf("\n"); driver->bad++; return -1; } } else { /* Deliver the event to the fifo */ } driver->good++; return 0; } /* Open all devices */ static struct device * open_devices(void) { struct device *dev = NULL, *tmp; DIR *dir; struct dirent *de; /* look for a USB mouse first */ if ((tmp = open_device("input/mouse0")) != 0) { tmp->next = dev; dev = tmp; } /* search /dev for something works */ /* XXX is this *really* a good idea? */ if (!(dir = opendir("/dev"))) { perror("/dev"); return NULL; } while ((de = readdir(dir)) != 0) { if ((tmp = open_device(de->d_name)) != 0) { tmp->next = dev; dev = tmp; } } closedir(dir); return dev; } static struct device * open_device(const char *name) { struct device temp, *dev; struct stat stb; struct mouse *driver = NULL; if (opt_verbose) { fprintf(stderr, "Opening device %s...\n", name); } memset(&temp, 0, sizeof(temp)); strcat(strcpy(temp.name, "/dev/"), name); if (!strncmp(name, DEV_SERIAL_PREFIX, sizeof(DEV_SERIAL_PREFIX) - 1)) { driver = get_mouse("serial"); temp.flags |= DEV_SERIAL_PORT; } #ifdef DEV_PSAUX_PREFIX else if (!strncmp(name, DEV_PSAUX_PREFIX, sizeof(DEV_PSAUX_PREFIX) - 1)) { driver = get_mouse("psaux"); } #endif #ifdef DEV_USB_PREFIX else if (!strncmp(name, DEV_USB_PREFIX, sizeof(DEV_USB_PREFIX) - 1)) { driver = get_mouse("usb"); } #endif #ifdef DEV_BUSMOUSE_PREFIX else if (!strncmp(name, DEV_BUSMOUSE_PREFIX, sizeof(DEV_BUSMOUSE_PREFIX) - 1)) { driver = get_mouse("sunmouse"); } #endif #ifdef __linux__ else { if (stat(temp.name, &stb) < 0 || !S_ISCHR(stb.st_mode)) return NULL; switch (major(stb.st_rdev)) { case 10: /* bus mice */ case 13: /* 2.4 kernel USB mice (really just 32-63) */ driver = get_mouse(name); break; } } #endif if (driver == NULL) return NULL; temp.driver = driver; if ((temp.fd = open(temp.name, O_RDWR)) < 0) return NULL; dev = (struct device *) malloc(sizeof(*dev)); memcpy(dev, &temp, sizeof(*dev)); if (dev->flags & DEV_SERIAL_PORT) tcgetattr(dev->fd, &dev->tty); if (driver->init) { if (dev->driver->init(dev, driver) < 0) { if (dev->flags & DEV_SERIAL_PORT) tcsetattr(dev->fd, TCSAFLUSH, &dev->tty); close(dev->fd); free(dev); return NULL; } } return dev; } mdetect/debian/0000755000000000000000000000000012033534306010612 5ustar mdetect/debian/copyright0000644000000000000000000001432511214402145012545 0ustar Package: mdetect Obtained from: openlinux.org CVS repository http://www.openlinux.org/lizard/devel-faq.html Upstream author: Caldera Systems, Inc. Debian package author: Branden Robinson Debian modifications to upstream sources: Sundry. This is essentially a fork of a very small portion of Caldera's "Lizard" system installation tool. Since mdetect does what I need it to, and because of the licensing, I do not intend to track upstream development. Richard Hirst supplied code to save and restore line settings on serial port devices. Original copyright: The files mdetect.c, mice.c, mdetect.h, and README are copyright (C) 1999 Caldera Systems, Inc., and are licensed under the Q Public License (QPL). The remainder of the files in this package are copyright (C) 2000 Progeny Linux Systems, Inc., and are licensed under the GNU General Public License (GPL); see /usr/share/common-licenses/GPL-2. To the extent that independent copyright is manifest in the changes that have been made to mdetect.c, mice.c, mdetect.h, and README as originally distributed by Caldera Systems, Inc., those changes are dual-licensed under the Q Public License (QPL), with the "Choice of Law" section stricken in its entirety, and simultaneously under the GNU General Public License (GPL); see /usr/share/common-licenses/GPL-2. The text of the Q Public License (QPL) as used by Caldera Systems, Inc. follows. THE Q PUBLIC LICENSE version 1.0 Copyright (C) 1999 Troll Tech AS, Norway. Everyone is permitted to copy and distribute this license document. The intent of this license is to establish freedom to share and change the software regulated by this license under the open source model. This license applies to any software containing a notice placed by the copyright holder saying that it may be distributed under the terms of the Q Public License version 1.0. Such software is herein referred to as the Software. This license covers modification and distribution of the Software, use of third-party application programs based on the Software, and development of free software which uses the Software. Granted Rights 1. You are granted the non-exclusive rights set forth in this license provided you agree to and comply with any and all conditions in this license. Whole or partial distribution of the Software, or software items that link with the Software, in any form signifies acceptance of this license. 2. You may copy and distribute the Software in unmodified form provided that the entire package, including - but not restricted to - copyright, trademark notices and disclaimers, as released by the initial developer of the Software, is distributed. 3. You may make modifications to the Software and distribute your modifications, in a form that is separate from the Software, such as patches. The following restrictions apply to modifications: a. Modifications must not alter or remove any copyright notices in the Software. b. When modifications to the Software are released under this license, a non-exclusive royalty-free right is granted to the initial developer of the Software to distribute your modification in future versions of the Software provided such versions remain available under these terms in addition to any other license(s) of the initial developer. 4. You may distribute machine-executable forms of the Software or machine-executable forms of modified versions of the Software, provided that you meet these restrictions: a. You must include this license document in the distribution. b. You must ensure that all recipients of the machine-executable forms are also able to receive the complete machine-readable source code to the distributed Software, including all modifications, without any charge beyond the costs of data transfer, and place prominent notices in the distribution explaining this. c. You must ensure that all modifications included in the machine-executable forms are available under the terms of this license. 5. You may use the original or modified versions of the Software to compile, link and run application programs legally developed by you or by others. 6. You may develop application programs, reusable components and other software items that link with the original or modified versions of the Software. These items, when distributed, are subject to the following requirements: a. You must ensure that all recipients of machine-executable forms of these items are also able to receive and use the complete machine-readable source code to the items without any charge beyond the costs of data transfer. b. You must explicitly license all recipients of your items to use and re-distribute original and modified versions of the items in both machine-executable and source code forms. The recipients must be able to do so without any charges whatsoever, and they must be able to re-distribute to anyone they choose. c. If the items are not available to the general public, and the initial developer of the Software requests a copy of the items, then you must supply one. Limitations of Liability In no event shall the initial developers or copyright holders be liable for any damages whatsoever, including - but not restricted to - lost revenue or profits or other direct, indirect, special, incidental or consequential damages, even if they have been advised of the possibility of such damages, except to the extent invariable law, if any, provides otherwise. No Warranty The Software and this license document are provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Choice of Law This license is governed by the Laws of the United States of America. Any disputes shall be conducted exclusively in state or federal court in the state of Utah. mdetect/debian/changelog0000644000000000000000000001001612033534306012462 0ustar mdetect (0.5.2.3build2) quantal; urgency=low * Rebuild for new armel compiler default of ARMv5t. -- Colin Watson Fri, 05 Oct 2012 11:39:02 +0100 mdetect (0.5.2.3build1) lucid; urgency=low * rebuild rest of main for armel armv7/thumb2 optimization; UbuntuSpec:mobile-lucid-arm-gcc-v7-thumb2 -- Alexander Sack Sun, 07 Mar 2010 00:56:56 +0100 mdetect (0.5.2.3) unstable; urgency=low * mdetect.c: Fix "mdetect ignores symlinks" by using stat() instead of lstat(). (Closes: #173326) * Upgrade the standard version. -- LIU Qi Thu, 16 Jul 2009 11:41:01 +0800 mdetect (0.5.2.2) unstable; urgency=low * New maintainer. (Closes: #522258) * Fixed many lintian warnings and an error. (Closes: #395751) -- LIU Qi Fri, 12 Jun 2009 11:48:25 +0800 mdetect (0.5.2.1) unstable; urgency=low * NMU with maintainer approval * Applied patch from Robert Millan to fix FTBFS on GNU/kFreeBSD and also to add mouse device names to detection logic (Closes: #319921) -- Otavio Salvador Fri, 28 Oct 2005 11:07:14 -0200 mdetect (0.5.2) unstable; urgency=low * Get right with Policy Version 3.5.7. * debian/control: - change Section to "utils" (Closes: #145101) - increment versioned build-dependency on debhelper to (>= 4.0) - increment Standards-Version to 3.5.7 * debian/rules: - use debhelper version 4 compatibility - support "noopt" flag in DEB_BUILD_OPTIONS - correct path in install rule -- Branden Robinson Wed, 2 Oct 2002 00:55:26 -0500 mdetect (0.5.1) unstable; urgency=low * the "how about running patch without the --dry-run option, dumbass" release * mdetect.{c,h}: really apply Richard Hirst's patch (Closes: #136115) -- Branden Robinson Wed, 27 Feb 2002 20:46:34 -0500 mdetect (0.5) unstable; urgency=low * mdetect.{c,h}: applied patch from Richard Hirst to save and restore terminal settings on serial devices; "Should be safe, all I'm doing is tcgetattr() and tcsetattr(), which the code did before anyway elsewhere. I registered an on_exit() function to ensure settings are restored on overall timeout. That meant calling exit(2) rather than _exit(2), so I restarted the timeout in case exit() itself hung. I restructured main() a bit, but I don't think that should cause problems; there was/is no way stage1() could return NULL anyway - it either detects something or exits via the alarm(). Tested on i386 and ia64, with ps/2 and serial mice (and no mice). serial mouse detection only works if I wiggle my mouse while mdetect runs, but that might be a feature of my mouse (and it ws the same before I changed the code). If that is expected behaviour, it should be in the manpage. If I have a serial console, then there is a little garbage on the line as mdetect runs and changes baudrate, but it recovers when mdetect exits." Thanks, Richard! (Closes: #131467) * mdetect.man: updated -- Branden Robinson Fri, 22 Feb 2002 18:02:05 -0500 mdetect (0.4) unstable; urgency=low * debian/control: add build-dependency on debhelper (>> 2.0) -- Branden Robinson Sat, 13 Oct 2001 20:38:26 -0500 mdetect (0.3) unstable; urgency=low * mdetect.c: search for USB mice on /dev/input/mouse0 first, so that non-USB mice are returned preferentially * mice.c: use ImPS/2 as X protocol on "kernel 2.4-style" USB mice -- Branden Robinson Fri, 16 Feb 2001 15:16:03 -0500 mdetect (0.2) unstable; urgency=low * mdetect.c: correct special-case IntelliMouse PS/2 logic so it actually works * mice.c: correct case of IntelliMouse XFree86 protocol name so that proper special-case PS/2 logic is invoked -- Branden Robinson Sun, 26 Nov 2000 18:58:19 -0500 mdetect (0.1) unstable; urgency=low * initial release -- Branden Robinson Sat, 25 Nov 2000 16:46:06 -0500 mdetect/debian/mdetect.files0000644000000000000000000000011207210060432013250 0ustar usr/bin/mdetect usr/share/man/man1/mdetect.1 usr/share/doc/mdetect/README mdetect/debian/control0000644000000000000000000000127311227522176012226 0ustar Source: mdetect Section: utils Priority: optional Maintainer: LIU Qi Build-Depends: debhelper (>= 7.0) Standards-Version: 3.8.2 Vcs-Browser: http://git.printk.org/?p=liuqi/debian/mdetect.git;a=summary Vcs-git: git://git.printk.org/liuqi/debian/mdetect.git Package: mdetect Architecture: any Depends: ${shlibs:Depends} Description: mouse device autodetection tool mdetect is a tool for autoconfiguring mice; it is typically used as the backend to some user-friendly frontend code. mdetect writes the autodetected mouse device and protocol (as used by gpm) to standard output. It can be invoked so as to produce output appropriate for XFree86 X server configuration files. mdetect/debian/rules0000755000000000000000000000222011215577311011672 0ustar #!/usr/bin/make -f # Debian package build rules file for mdetect # Copyright (C) 2000 Progeny Linux Systems, Inc. # Author: Branden Robinson # Licensed under the GNU General Public License, version 2. See the file # /usr/share/common-licenses/GPL or . # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 CFLAGS=-g -Wall # Does DEB_BUILD_OPTIONS contain the "noopt" flag? ifeq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) # don't get rid of the space in the next line CFLAGS+= -O2 endif build: build-stamp build-stamp: dh_testdir $(MAKE) CFLAGS="$(CFLAGS)" touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp $(MAKE) clean dh_clean install: build dh_testdir dh_testroot dh_prep dh_installdirs $(MAKE) PREFIX=$(CURDIR)/debian/mdetect install binary-arch: build install dh_testdir dh_testroot dh_installdocs #dh_installmanpages dh_installchangelogs dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary-indep: binary: binary-arch binary-indep .PHONY: build clean install binary-arch binary-indep binary mdetect/debian/compat0000644000000000000000000000000211214402007012000 0ustar 7 mdetect/mdetect.man0000644000000000000000000001006107435552213011517 0ustar .\" This manpage is copyright (C) 2000 Progeny Linux Systems, Inc. .\" Author: Branden Robinson .\" .\" This is free software; you may 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, .\" or (at your option) any later version. .\" .\" This 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 the Debian GNU/Linux system; if not, write to the Free .\" Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA .\" 02111-1307 USA .\" .\" That's right, although mdetect itself is under the QPL, this manpage is .\" under the GPL. Enjoy! .TH mdetect 1 "2002-02-22" "Debian GNU/Linux" .SH NAME mdetect \- mouse device autodetection tool .SH SYNOPSIS mdetect [\fIoption ...\fP] .SH OPTIONS mdetect may be run without arguments. .TP .B -h display a help message and exit .TP .B -n do not search for PnP (Plug 'n' Play) mice .TP .B -r [not yet implemented] .TP .B -v be verbose; this option may be specified multiple times for increasing levels of verbosity .TP .B -o produce output appropriate for XFree86 3.x configuration .TP .B -x produce output appropriate for XFree86 4.x configuration .SH DESCRIPTION .B mdetect is a tool for autoconfiguring mice and compatible pointing devices; it is typically used as the backend to some user-friendly frontend code that, for example, asks the user to move the mouse for a moment. .B mdetect is then run while user is producing input on the mouse device. While mouse motion during detection is sometimes unnecessary, it is seldom problematic. .PP .B mdetect writes the autodetected mouse device and protocol to standard output. Unless either of the .B -o or .B -x options is given, .B mdetect produces output appropriate for configuring the .BR gpm (1) program. Alternatively, output appropriate for an XFree86 X server configuration file is produced. If the .B -v option is given, some information about the program's status is also written to standard output, but this is largely unimplemented at this writing. .PP If .B mdetect is unable to find a mouse device, it exits after a few seconds of searching. .SH NOTES Detection of serial and PS/2 devices is often aided by moving the mouse while .B mdetect runs. .PP Terminals connected to serial ports may display a small amount of garbage to the screen while .B mdetect probes them, but this a harmless side-effect; the terminal's line settings are restored after the port has been probed. .SH DIAGNOSTICS .BR mdetect 's exit status is used to communicate information. .IP 0 .B mdetect found a mouse and exited normally. .IP 1 An error occurred while attempting to read from the mouse device. .IP 2 .B mdetect timed out and gave up searching for a mouse device; this indicates either that no mouse device is attached to the computer, or that a mouse device exists which .B mdetect knows nothing about. This also happens if your only mouse device(s) are already open and in use; for instance, by .B gpm or an X Window System server. .IP 3 An error occurred while trying to set up .BR mdetect 's signal handler. .SH BUGS Please report bugs in .B mdetect to . The current bug list may be viewed at . .SH AUTHORS .B mdetect is copyright 1999 Caldera Systems, Inc. The actual authors are unknown. Branden Robinson of Progeny Linux Systems, Inc. and the Debian Project added several enhancements, including the XFree86-aware code and this manual page. Richard Hirst wrote code to save and restore serial port settings. .SH LICENSING The .B mdetect source code is licensed under the Q Public License (QPL); see . .PP This manual page is licensed under the GNU General Public License. .SH SEE ALSO .IR gpm (1), .IR XFree86 (1) mdetect/README0000644000000000000000000000601707210021772010253 0ustar The Mouse Detective :-) This is an incomplete program for mouse detection. The idea is to use it in some kind of dialog that says: try to move your mouse and click on the OK button. If this doesn't work, enter return [the keyboard focus is on cancel]. Use it like this: $ ./mdetect -v Found the following devices: /dev/ttyS1 /dev/ttyS0 /dev/psaux [start moving mouse] microsoft: 105 102 logitech: LM -27 27 microsoft: L 6 -43 logitech: LM 93 191 microsoft: 7 -7 Detected microsoft mouse on /dev/ttyS0 You can see it switching between logitech and microsoft mode until it settles on microsoft mode. Invoking it without the -v switch disables all output except for the `Detected ... mouse' line. Currently, the following mice are reported: psaux PS/2 mousesystems MouseSystems compatible microsoft Old Microsoft protocol logitech Some (old) logitech mice mouseman MouseMan (microsoft with 3/4 packet extension) Here's a framework that I think might work 1. Start the mouse detection program 2. Start X server, display dialog 3. User starts moving the mouse 4. Detection program tries to understand what the mouse tries to say (this is stage1). It should arrive at a decision within 1 sec. 5a. Detection program has decided on a driver. Enters stage2, where it writes the mouse packets it received into a fifo (but now, in a mouse-type independent packet format). This is basically what gpm -R does. Pointer starts to move on the screen. 5b. Detection Program wasn't able to detect mouse type. It doesn't do anything. Pointer doesn't move, user has to select mouse manually. NB: How does XF86Config set the mouse type? I assume there's an X extension? If so, in step 5, we can also tell the X server what mouse to use (if we know what to use), and exit. This is a lot better than the fifo approach. Mode of Operation What the program does is open all available devices for reading. Whenever it gets a byte, it lets all drivers (currently psaux, microsoft, logitech) have a look at it. If the driver can make sense of the packet, fine. If any driver is able to successfully decode 20 mouse packets in a row, it is considered _the_ driver. Serial mice are a bit special, since they use different line settings etc. So there's a serial 'meta' driver that sets the line characteristics to those of each driver in turn. Currently, I'm able to detect either ps2 or an M$-compatible mouse fairly reliably. I haven't tested the logitech code. If you don't jiggle the mouse too hard, detection is faster; otherwise, it will start with a few false guesses before settling on the right one. Good packets are those that can be decoded, have reasonable dx/dy values and no mouse button pressed. (this might be improved by looking at the second derivative, so to speak: changes in dx/dy values sent by the mouse shouldn't be too large). The question is whether this is really worth the trouble. Maybe we will have as high a success rate if we use ps2 when able to open the device; and ttyS0 with the M$ protocol otherwise. mdetect/mdetect.h0000644000000000000000000000350510330420554011166 0ustar /* * Mouse detection * * Copyright (C) 1999, Caldera System Inc */ #ifndef MDETECT_H #define MDETECT_H struct device { struct device * next; char name[64]; int fd; struct mouse * driver; unsigned long timeout; /* When packet should be complete */ int flags; #define DEV_DRIVER_FOUND 0x01 #define DEV_SERIAL_PORT 0x02 struct termios tty; }; struct mouse { const char * name; const char * xfree86_protocol_name; int (*init)(struct device *, struct mouse *); int (*packet)(struct device *, struct mouse *, unsigned char); int (*timeout)(struct device *); const char * (*report)(struct mouse *); struct mouse * next; struct mouse * alt; void * data; unsigned char buffer[256]; unsigned int cur, got; unsigned int total; /* total byte count */ unsigned int good; unsigned int bad; unsigned int flags; #define FLAG_MS_WEIRDO 0x01 /* could be serial m$ 3/5 proto */ unsigned int buttons; #define BUTTON_RIGHT 0x01 #define BUTTON_MIDDLE 0x02 #define BUTTON_LEFT 0x04 int dx, dy, dz; int lx, ly, lz; /* last dx/dy, for 2nd derivative */ }; #define MIN_GOOD_EVENTS 20 /* Number of good events after which * we accept a driver */ #define SERIAL_IDLE_TIMEOUT 100 /* If we don't see at least one * event after 100ms, we switch * to the next serial device */ #define SERIAL_NOISE_MAX 8 /* Max number of bad chars after * which we switch to the next driver */ struct mouse * get_mouse(const char *); int send_event(struct mouse *); void serialdev_init(struct device *); extern int opt_verbose; extern int opt_nopnp; #if defined(__linux__) # define DEV_SERIAL_PREFIX "ttyS" #elif defined(__FreeBSD_kernel__) # define DEV_SERIAL_PREFIX "cuaa" # define DEV_PSAUX_PREFIX "psm" # define DEV_USB_PREFIX "ums" # define DEV_BUSMOUSE_PREFIX "mse" #endif #endif /* MDETECT_H */ mdetect/mice.c0000644000000000000000000003442510330420554010456 0ustar #include #include #include #include #include #include #include #include "mdetect.h" extern int opt_xf86config; static int flush(struct device *dev, char *buffer, unsigned int size) { char x; int j, n = 0; fcntl(dev->fd, F_SETFL, O_NDELAY); while (n < size && read(dev->fd, &x, 1) > 0) { if (buffer) buffer[n] = x; n++; } fcntl(dev->fd, F_SETFL, 0); if (n && opt_verbose > 2) { printf("Read %d chars from %s: ", n, dev->name); for (j = 0; j < n; j++) printf(isprint(buffer[j])? "%c" : "\\%03o", (unsigned char) buffer[j]); printf("\n"); } return n; } static void _setflags(struct device *dev, int flags) { struct termios tty; tcgetattr(dev->fd, &tty); tty.c_iflag = IGNBRK | IGNPAR; tty.c_oflag = 0; tty.c_lflag = 0; tty.c_cflag = flags | CREAD | CLOCAL | HUPCL; /* c_line is not POSIX */ #ifdef __linux__ tty.c_line = 0; #endif tty.c_cc[VTIME] = 0; tty.c_cc[VMIN] = 1; tcsetattr(dev->fd, TCSAFLUSH, &tty); } static void setflags(struct device *dev, int flags) { _setflags(dev, flags | B1200); flush(dev, NULL, 10); } void serialdev_init(struct device *dev) { int n, speed[4] = { B9600, B4800, B2400, B1200 }; char buffer[10]; /* Tell the mouse at what speed it should report. * We need the loop so we're sure it understands what we * tell it. */ for (n = 0; n < 4; n++) { _setflags(dev, CSTOPB|speed[n]); write(dev->fd, "*q", 2); usleep(10000); } /* gpm hack */ if (flush(dev, buffer, 10) == 2 && buffer[1] == 0x33) { struct mouse *driver; driver = (struct mouse *) dev->driver->alt; while (driver) { if (!strcmp(driver->name, "microsoft")) driver->name = "mouseman"; driver = driver->next; } } } static int serialdev_event(struct mouse *driver) { if (driver->good == 0) { driver->lx = driver->dx; driver->ly = driver->dy; } if (send_event(driver) >= 0 || driver->good) { driver->got = 0; } else { driver->buffer[0] = driver->buffer[1]; driver->buffer[1] = driver->buffer[2]; driver->buffer[2] = driver->buffer[3]; driver->got--; } driver->lx = driver->dx; driver->ly = driver->dy; return 0; } static int init_logitech(struct device *dev, struct mouse *driver) { setflags(dev, CSTOPB | CS8 | PARENB | PARODD); /* logitech magic */ if (write(dev->fd, "S", 1) < 0) return -1; /* 60 samples per sec */ if (write(dev->fd, "R", 1) < 0) return -1; return 0; } static int packet_logitech(struct device *dev, struct mouse *driver, unsigned char c) { unsigned char *data = driver->buffer; /* printf("%02x ", c); fflush(stdout); */ driver->buffer[driver->got++] = c; switch (driver->got) { case 1: if ((c & 0xE0) != 0x80) { driver->got = 0; return 0; } return 0; case 2: if ((c & 0x80) != 0x00) { driver->got = 0; return -1; } return 0; } driver->buttons = data[0] & 0x7; driver->dx = (data[0] & 0x10)? data[1] : -data[1]; driver->dy = (data[0] & 0x20)? -data[2] : data[2]; return serialdev_event(driver); } static int init_ms(struct device *dev, struct mouse *driver) { setflags(dev, CS7); /* 60 samples per sec */ if (write(dev->fd, "R", 1) < 0) return -1; return 0; } /* When testing this with some logitechs, I noticed that they send * an additional byte for middle-button (0x20 while button is pressed, * 0x00 once when released). Wheark. * (I later found out that this is the mouse man protocol; so replace * s/weirdo/mouseman/g below). */ static int packet_ms(struct device *dev, struct mouse *driver, unsigned char c) { unsigned char *data = driver->buffer; int middledown = 0, weirdo = 0; middledown = (driver->buttons & BUTTON_MIDDLE); weirdo = driver->flags & FLAG_MS_WEIRDO; driver->buffer[driver->got++] = c; switch (driver->got) { case 1: if ((c & 0x40) != 0x40) { if (c == 0x20 && middledown && !weirdo) driver->flags |= FLAG_MS_WEIRDO; driver->got = 0; return 0; } return 0; case 2: if ((c & 0x40) != 0x00) { driver->got = 0; return -1; } return 0; case 3: /* waiting for fourth byte? */ if (weirdo && middledown) return 0; } /* M$ 3button extension: a packet of 0x40 0x00 0x00, valid * only if the other two buttons have been released. */ if (data[0] == 0x40 && !(driver->buttons | data[1] | data[2])) { driver->buttons = BUTTON_MIDDLE; } else { driver->buttons = ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4); if (weirdo && middledown && data[3] == 0x20) driver->buttons |= BUTTON_MIDDLE; } driver->dx = (char) ((data[0] & 0x3) << 6) | (data[1] & 0x3f); driver->dy = (char) ((data[0] & 0xC) << 4) | (data[2] & 0x3f); return serialdev_event(driver); } static const char * report_ms(struct mouse *driver) { if (driver->flags & FLAG_MS_WEIRDO) return "mouseman"; return driver->name; } /* Mouse-systems compatible */ static int init_msc(struct device *dev, struct mouse *driver) { setflags(dev, CS8|CSTOPB); /* 60 samples per sec */ if (write(dev->fd, "R", 1) < 0) return -1; return 0; } static int packet_msc(struct device *dev, struct mouse *driver, unsigned char c) { unsigned char *data = driver->buffer; /* printf("msc: %02x\n", c); */ driver->buffer[driver->got++] = c; switch (driver->got) { case 1: if ((c & 0xf8) != 0x80) { driver->got = 0; return 0; } return 0; case 2: case 3: case 4: return 0; } driver->buttons = (~data[0]) & 0x7; driver->dx = (char) data[1] + (char) data[3]; driver->dy = -(char) data[2] + (char) data[4]; return serialdev_event(driver); } static void next_serial(struct device *dev, struct mouse *driver) { struct mouse *sub; sub = (struct mouse *) driver->data; if (!(sub = sub->next)) sub = driver->alt; while (sub && sub->init(dev, sub) < 0) sub = sub->next; driver->data = sub; if (opt_verbose) { printf("\n %s\r", sub->name); fflush(stdout); } /* Now clean all driver state */ driver->total = 0; for (sub = driver->alt; sub; sub = sub->next) { sub->good = sub->bad = 0; sub->got = sub->total = 0; sub->timeout = 0; sub->flags = 0; } } static int init_serial(struct device *dev, struct mouse *driver) { struct mouse *sub; /* Initialize the serial device */ serialdev_init(dev); /* Remove any devices we can't initialize */ while ((sub = driver->alt) != NULL && sub->init(dev, sub) < 0) driver->alt = sub->next; if (!(driver->data = sub)) return -1; return 0; } static int packet_serial(struct device *dev, struct mouse *driver, unsigned char c) { struct mouse *sub; int okay = 0; if (!(sub = driver->alt)) return -1; sub = (struct mouse *) driver->data; sub->total++; if (opt_verbose) { printf("%3d %s\r", sub->total, sub->name); fflush(stdout); } driver->total++; driver->good = 0; dev->timeout = 0; if (!sub->bad && sub->packet(dev, sub, c) >= 0) { if (sub->good > driver->good) { driver->good = sub->good; if (sub->good >= MIN_GOOD_EVENTS) { dev->driver = sub; dev->timeout = 0; return 0; } } if (sub->got) dev->timeout = 10; okay++; } if (driver->good == 0) { if (driver->total > SERIAL_NOISE_MAX) next_serial(dev, driver); else if (dev->timeout == 0) dev->timeout = 100; } return 0; } static int timeout_serial(struct device *dev) { next_serial(dev, dev->driver); return 0; } static int init_psaux(struct device *dev, struct mouse *driver) { static unsigned char query[] = { 0xF2 }; static unsigned char init[] = { 243, 200, 243, 100, 243, 80 }; char buffer[20]; int n; if (opt_verbose > 1) printf("%s sending intellimouse init sequence.\n", dev->name); write(dev->fd, init, sizeof(init)); usleep(10000); flush(dev, buffer, 20); if (opt_verbose > 1) printf("%s querying PS/2 ID.\n", dev->name); write(dev->fd, query, sizeof(query)); usleep(10000); if ((n = flush(dev, buffer, 20)) > 0) { const char *type = NULL; struct mouse *m; switch(buffer[n-1]) { case 0: type = "psaux"; break; case 3: /* 3button + Z format */ case 4: /* 5button + Z format */ type = "intellimouse"; break; } if (type && opt_verbose) printf("%s says it's a %s mouse\n", dev->name, type); if (type && !opt_nopnp) { for (m = driver; m; m = m->next) { if (!strcmp(m->name, type)) { dev->driver = m; dev->flags |= DEV_DRIVER_FOUND; return 0; } } } } /* Detection failed. Try to reset mouse */ #if 0 { static unsigned char reset[] = { 0xff }; write(dev->fd, &reset, 1); close(dev->fd); if ((dev->fd = open(dev->name, O_RDWR)) < 0) { dev->fd = -1; return -1; } } #endif return 0; } static int packet_psaux(struct device *dev, struct mouse *driver, unsigned char c) { driver->buffer[driver->got++] = c; driver->total++; if (driver->got == 3) { unsigned char *d = driver->buffer; /* The top two bits are the overflow bits. * They get set when the mouse delta exceeds 255. */ if (d[0] & 0xc0) goto bad; /* The PS/2 docs on the M$ hwdev web pages say * this bit is always on. */ if (!(d[0] & 8)) goto bad; driver->buttons = ((d[0] & 1) << 2) | ((d[0] & 4) >> 1) | ((d[0] & 2) >> 1); driver->dx = (d[0] & 0x10)? d[1] - 256 : d[1]; driver->dy = (d[0] & 0x20)? d[2] - 256 : d[2]; if (send_event(driver) < 0) goto bad; driver->got = 0; } out: dev->timeout = driver->got? 10 : 0; return 0; bad: if (driver->total > 20) { #if 0 if ((driver = driver->next) == NULL) return -1; if (opt_verbose > 2) printf("psaux out of sync, switching next.\n"); dev->driver = driver; if (driver->init) driver->init(dev, driver); #else return -1; #endif } else { /* Eat the first character and discard it */ if (opt_verbose > 2) printf("psaux out of sync, trying to resync.\n"); memmove(driver->buffer, driver->buffer+1, driver->got - 1); driver->got--; } goto out; } static int packet_usb(struct device *dev, struct mouse *driver, unsigned char c) { driver->buffer[driver->got++] = c; driver->total++; if (driver->got == 3) { unsigned char *d = driver->buffer; /* The top two bits are the overflow bits. * They get set when the mouse delta exceeds 255. */ if (d[0] & 0xc0) goto bad; driver->buttons = ((d[0] & 1) << 2) | ((d[0] & 4) >> 1) | ((d[0] & 2) >> 1); driver->dx = (d[0] & 0x10)? d[1] - 256 : d[1]; driver->dy = (d[0] & 0x20)? d[2] - 256 : d[2]; if (send_event(driver) < 0) goto bad; driver->got = 0; } out: dev->timeout = driver->got? 10 : 0; return 0; bad: if (driver->total > 20) { return -1; } /* Eat the first character and discard it */ if (opt_verbose > 2) printf("psaux out of sync, trying to resync.\n"); memmove(driver->buffer, driver->buffer+1, driver->got - 1); driver->got--; goto out; } static int timeout_psaux(struct device *dev) { struct mouse *driver = dev->driver; if (driver->total < 20) { driver->got = 0; dev->timeout = 0; return 0; } return -1; } static int packet_sunmouse(struct device *dev, struct mouse *driver, unsigned char c) { /* if we get bytes from driver then we detected a sun mouse... */ dev->flags |= DEV_DRIVER_FOUND; return 0; } static int init_usb24(struct device *dev, struct mouse *driver) { dev->flags |= DEV_DRIVER_FOUND; return 0; } static int packet_usb24(struct device *dev, struct mouse *driver, unsigned char c) { return 0; } static struct mouse mouse_msc = { "mousesystems", "MouseSystems", /* XFree86 mouse driver protocol name */ init_msc, /* init code */ packet_msc, /* packet handler */ NULL, /* timeout */ NULL, /* report */ NULL, /* next */ NULL, /* alt */ NULL, /* data */ }; static struct mouse mouse_ms = { "microsoft", "Microsoft", /* XFree86 mouse driver protocol name */ init_ms, /* init code */ packet_ms, /* packet handler */ NULL, /* timeout */ report_ms, /* report */ &mouse_msc, /* next */ NULL, /* alt */ NULL, /* data */ }; static struct mouse mouse_logitech = { "logitech", "Logitech", /* XFree86 mouse driver protocol name */ init_logitech, /* init code */ packet_logitech, /* packet handler */ NULL, /* timeout */ NULL, /* report */ &mouse_ms, /* next */ NULL, /* alt */ NULL, /* data */ }; static struct mouse mouse_serial = { "serial", "Auto", /* XFree86 mouse driver protocol name */ init_serial, /* init code */ packet_serial, /* packet handler */ timeout_serial, /* timeout */ NULL, /* report */ NULL, /* next */ &mouse_logitech, /* alt */ &mouse_logitech, /* currently initialized */ }; static struct mouse mouse_intelli = { "intellimouse", "IntelliMouse", /* XFree86 mouse driver protocol name */ init_psaux, /* init code */ packet_psaux, /* packet handler */ timeout_psaux, /* timeout */ NULL, /* report */ }; static struct mouse mouse_psaux = { "psaux", "PS/2", /* XFree86 mouse driver protocol name */ init_psaux, /* init code */ packet_psaux, /* packet handler */ timeout_psaux, /* timeout */ NULL, /* report */ &mouse_intelli, }; static struct mouse mouse_usb = { "USB", "USB", /* XFree86 mouse driver protocol name */ NULL, /* init code */ packet_usb, /* same as ps/2 mice */ timeout_psaux, /* timeout */ NULL, /* report */ }; static struct mouse mouse_sunmouse = { "sunmouse", "SysMouse", /* XFree86 mouse driver protocol name XXX correct? */ NULL, /* init code */ packet_sunmouse, /* packet handler */ NULL, /* timeout */ NULL, /* report */ }; static struct mouse mouse_usb24 = { "USB", "ImPS/2", /* XFree86 mouse driver protocol name */ init_usb24, /* init code */ packet_usb24, /* packet handler */ NULL, /* timeout */ NULL, /* report */ }; /* Return the mouse driver for a device file name */ static struct mouse * find_mouse(const char *name) { if (!strcmp(name, "serial")) return &mouse_serial; if (!strcmp(name, "psaux")) return &mouse_psaux; if (!strcmp(name, "usb") || !strcmp(name, "hidbp-mse-0")) return &mouse_usb; if (!strncmp(name, "input/mouse", 11)) return &mouse_usb24; if (!strcmp(name, "sunmouse")) return &mouse_sunmouse; return NULL; } static struct mouse * clone_mouse(struct mouse *driver) { struct mouse *tmp; tmp = (struct mouse *) malloc(sizeof(*driver)); memcpy(tmp, driver, sizeof(*tmp)); driver = tmp; if (driver->alt) driver->alt = clone_mouse(driver->alt); if (driver->next) driver->next = clone_mouse(driver->next); return driver; } struct mouse * get_mouse(const char *name) { struct mouse *driver; if (!(driver = find_mouse(name))) return NULL; return clone_mouse(driver); } mdetect/Makefile0000644000000000000000000000244511215574601011040 0ustar #!/usr/bin/make -f # Copyright (C) 2000 Progeny Linux Systems, Inc. # Author: Branden Robinson # # This is free software; you may 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, # or (at your option) any later version. # # This 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 the Debian GNU/Linux system; if not, write to the Free # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # That's right, although mdetect itself is under the QPL, this makefile is # under the GPL. Enjoy! CFLAGS=-Wall -g -O2 mdetect: mdetect.c mice.c install: mdetect install -m 755 -d $(PREFIX)/usr/bin install -m 755 mdetect $(PREFIX)/usr/bin install -m 755 -d $(PREFIX)/usr/share/man/man1 install -m 644 mdetect.man $(PREFIX)/usr/share/man/man1/mdetect.1 install -m 755 -d $(PREFIX)/usr/share/doc/mdetect install -m 644 README $(PREFIX)/usr/share/doc/mdetect clean: rm -f mdetect *.o core