diff -ruN /usr/src.orig/include/Makefile /usr/src/include/Makefile --- /usr/src.orig/include/Makefile Thu Mar 30 15:15:53 2006 +++ /usr/src/include/Makefile Thu Apr 13 20:29:40 2006 @@ -63,6 +63,10 @@ INCS+= hesiod.h .endif +.if defined(NEWMOUSE) +INCS+= moused.h ps2.h +.endif + .if ${MK_BLUETOOTH} != "no" LSUBSUBDIRS= netgraph/bluetooth/include .endif diff -ruN /usr/src.orig/include/moused.h /usr/src/include/moused.h --- /usr/src.orig/include/moused.h Wed Dec 31 19:00:00 1969 +++ /usr/src/include/moused.h Wed Mar 29 01:45:09 2006 @@ -0,0 +1,83 @@ + +#ifndef MOUSED_H +#define MOUSED_H + +#include +#include +#include + +struct rodentparam; +typedef struct rodentparam rodent_t; + +#define FLAG_VIRTUAL_SCROLL 0x10 +#define FLAG_EMULATE_3_BUTTON 0x20 +#define FLAG_ACCELERATION 0x40 +#define FLAG_CHORD_MIDDLE 0x80 + +struct rodentparam { + char *device; + char *modulename; + char *configfile; + int cfd; /* /dev/consolectl fd */ + int mfd; /* mouse device fd */ + + int verbose; + mousemode_t mode; + //mousehw_t hw; + mouse_info_t state; + + char *packet; /* Used repeatedly by a plugin, keep it here */ + struct timeval sleeptime; /* Timeout for select(2) call */ + int flags; + short emulate3_timeout; + short virtual_scroll_threshold; + float accelx; + float accely; + + /* Modules will call this to pass deltas to sysmouse(4) */ + int (*update)(struct mouse_info *); + void (*logmsg)(int, int, const char *, ...); + + /* Module callbacks (called by moused) */ + int (*init)(rodent_t *, int, char **); + int (*probe)(rodent_t *); + void (*run)(rodent_t *); /* for standalone mode */ + + void (*handler)(rodent_t *); /* for packet-handler mode */ + void (*handler_init)(rodent_t *); /* for packet-handler init*/ + + void (*timeout)(rodent_t *); /* select(2) timeouts call this + * when in handler mode */ + + /* Config */ + char *config; /* cgetent buffer */ +}; + +#define MOUSED_INIT_FUNC int init(rodent_t *rodent, int argc, char **argv) +#define MOUSED_PROBE_FUNC int probe(rodent_t *rodent) +#define MOUSED_HANDLER_FUNC void handler(rodent_t *rodent) +#define MOUSED_HANDLER_INIT_FUNC void handler_init(rodent_t *rodent) + +/* + * *** XXX:DEPRECATED *** + * Should this (RUN) method even be allowed? Is it useful to have the plugin + * handle things like select(2) calls and such? + */ +#define MOUSED_RUN_FUNC void run(rodent_t *rodent) + +/* Probe function return values */ +#define MODULE_PROBE_FAIL 0 +#define MODULE_PROBE_SUCCESS 1 + +/* Bit math, helpful for modules */ +#define BIT(num, bit) (((num) & (1 << (bit - 1))) ? 1 : 0) +#define NBIT(num, bit) ((BIT(num,bit)) ^ 1) + +#define logfatal(e, fmt, args...) do { \ + logmsg(LOG_DAEMON | LOG_ERR, errno, fmt, ##args); \ + exit(e); \ +} while (0) + +#endif + + diff -ruN /usr/src.orig/include/ps2.h /usr/src/include/ps2.h --- /usr/src.orig/include/ps2.h Wed Dec 31 19:00:00 1969 +++ /usr/src/include/ps2.h Thu Apr 13 20:54:34 2006 @@ -0,0 +1,18 @@ + +int ps2_open(char *dev); +int ps2_openfd(int fd); +int ps2_reset(); +int ps2_get_status(char *status); +int ps2_set_resolution(int resolution); +int ps2_set_sample_rate(int rate); + +int ps2_disable_stream(); +int ps2_enable_stream(); + +int ps2_mousefd(); + +int ps2_ext_command(int command); +int ps2_set_packetsize(int size); +int ps2_set_syncmask(unsigned char syncmask); + +int ps2_set_scaling(int scale); diff -ruN /usr/src.orig/lib/Makefile /usr/src/lib/Makefile --- /usr/src.orig/lib/Makefile Mon Mar 20 09:24:57 2006 +++ /usr/src/lib/Makefile Thu Apr 13 15:08:07 2006 @@ -36,7 +36,7 @@ libpmc ${_libpthread} librt ${_libsdp} ${_libsm} ${_libsmb} \ ${_libsmdb} \ ${_libsmutil} libstand libtelnet ${_libthr} ${_libthread_db} libufs \ - libugidfw ${_libusbhid} ${_libvgl} libwrap liby libz ${_bind} + libugidfw ${_libusbhid} ${_libvgl} libwrap liby libz ${_bind} ${_ps2} .if exists(${.CURDIR}/csu/${MACHINE_ARCH}-elf) _csu=csu/${MACHINE_ARCH}-elf @@ -62,6 +62,10 @@ .if ${MK_IPX} != "no" _libipx= libipx +.endif + +.if defined(NEWMOUSE) +_ps2= libps2 .endif .if ${MACHINE_ARCH} == "i386" diff -ruN /usr/src.orig/lib/libps2/Makefile /usr/src/lib/libps2/Makefile --- /usr/src.orig/lib/libps2/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/lib/libps2/Makefile Thu Apr 13 20:40:29 2006 @@ -0,0 +1,11 @@ +LIB=ps2 +SHLIBDIR?= /lib + +SRCS= ps2.c +INCS= ps2_protocol.h ps2.h +#INCS= moused.h ./ps2_protocol.h ./ps2.h + +# XXX: Hack - This is needed to convince bsd.lib.mk to build a shared library +SHLIB_MAJOR=1 + +.include diff -ruN /usr/src.orig/lib/libps2/ps2.c /usr/src/lib/libps2/ps2.c --- /usr/src.orig/lib/libps2/ps2.c Wed Dec 31 19:00:00 1969 +++ /usr/src/lib/libps2/ps2.c Tue Mar 21 22:35:17 2006 @@ -0,0 +1,183 @@ +/* + * Happy ps/2 protocol library + * + * Ideally, we should provide an api for talking to mice and caring less about + * what happens underneath. + */ + +#include + +/* XXX: These should disappear when newpsm(4) is done, right? */ +#include +#include +/* Hurray! */ + +#include +#include +#include +#include +#include + +#include "ps2_protocol.h" + +#define NODATA -1 + +static int mfd; + +int ps2_open(char *dev) { + int level; + int hwid = 0; + mousecommand_t mc; + char status[3]; + + mfd = open(dev, O_RDWR); + + if (mfd == -1) { + warnx("Failure opening %s: %s", dev, strerror(errno)); + return -1; + } + + return 0; +} + +int ps2_openfd(int fd) { + mfd = fd; + return 0; +} + +int send_command(int cmd, char data, char *response, int responselen) { + mousecommand_t mc; + int ret; + + mc.command = cmd; + mc.data = data; + mc.response = response; + mc.responselen = responselen; + + /* XXX: Is this necessary? */ + /* Ensure we can access this portion of memory before going into kernel mode */ + *(response + responselen - 1); + + ret = ioctl(mfd, MOUSE_COMMAND, &mc); + + //warnx("libps2: ioctl: %d", ret); + + return ret; +} + +int ps2_reset() { + return send_command(COMMAND_RESET, NODATA, NULL, 0); +} + +int ps2_get_status(char *status) { + int ret; + char res[3]; + + ret = send_command(COMMAND_STATUS_REQUEST, NODATA, res, 3); + + memcpy(status,res,3); + + return ret; +} + +int ps2_set_resolution(int resolution) { + int ret; + char data; + + /* Valid resolutions are 0-3 */ + assert(resolution >= 0 && resolution <= 3); + + /* Ensure resolution is only 2 bits wide */ + data = resolution & 0x03; + ret = send_command(COMMAND_SET_RESOLUTION, data, NULL, 0); + + return ret; +} + +int ps2_set_sample_rate(int rate) { + int ret; + + /* Valid sample rates */ + assert(rate == 10 || rate == 20 || rate == 40 || rate == 60 + || rate == 80 || rate == 100 || rate == 200); + + ret = send_command(COMMAND_SET_SAMPLE_RATE, rate, NULL, 0); + + return ret; +} + +int ps2_disable_stream() { + int ret; + + ret = send_command(COMMAND_DISABLE_REPORTING, NODATA, NULL, 0); + return ret; +} + +int ps2_enable_stream() { + int ret; + + ret = send_command(COMMAND_ENABLE_REPORTING, NODATA, NULL, 0); + return ret; +} + +int ps2_mousefd() { + return mfd; +} + +int ps2_set_remote_mode() { + int ret; + + ret = send_command(COMMAND_SET_REMOTE_MODE, NODATA, NULL, 0); + return ret; +} + +/* + * XXX: Write this? + * Keep track of packet size when we call ps2_set_packetsize, use it here. + */ +int ps2_read_data(char *data, int datalen) { + +} + +int ps2_ext_command(int command) { + int c; + + c = (command >> 6) & 0x03; + if (ps2_set_resolution(c) != 0) + return 1; + + c = (command >> 4) & 0x03; + if (ps2_set_resolution(c) != 0) + return 1; + + c = (command >> 2) & 0x03; + if (ps2_set_resolution(c) != 0) + return 1; + + c = (command >> 0) & 0x03; + if (ps2_set_resolution(c) != 0) + return 1; + return 0; +} + +int ps2_set_packetsize(int size) { + int ret; + + ret = ioctl(mfd, MOUSE_SET_PACKETSIZE, &size); + return ret; +} + +int ps2_set_syncmask(unsigned char syncmask) { + int ret; + + ret = ioctl(mfd, MOUSE_SET_SYNCMASK, &syncmask); + return ret; +} + +int ps2_set_scaling(int scale) { + if (scale == 1) + return send_command(COMMAND_SET_MOUSE_SCALING11, NODATA, NULL, 0); + else if (scale == 2) + return send_command(COMMAND_SET_MOUSE_SCALING21, NODATA, NULL, 0); + return -1; +} diff -ruN /usr/src.orig/lib/libps2/ps2.h /usr/src/lib/libps2/ps2.h --- /usr/src.orig/lib/libps2/ps2.h Wed Dec 31 19:00:00 1969 +++ /usr/src/lib/libps2/ps2.h Mon Dec 26 04:49:03 2005 @@ -0,0 +1,18 @@ + +int ps2_open(char *dev); +int ps2_openfd(int fd); +int ps2_reset(); +int ps2_get_status(char *status); +int ps2_set_resolution(int resolution); +int ps2_set_sample_rate(int rate); + +int ps2_disable_stream(); +int ps2_enable_stream(); + +int ps2_mousefd(); + +int ps2_ext_command(int command); +int ps2_set_packetsize(int size); +int ps2_set_syncmask(unsigned char syncmask); + +int ps2_set_scaling(int scale); diff -ruN /usr/src.orig/lib/libps2/ps2_protocol.h /usr/src/lib/libps2/ps2_protocol.h --- /usr/src.orig/lib/libps2/ps2_protocol.h Wed Dec 31 19:00:00 1969 +++ /usr/src/lib/libps2/ps2_protocol.h Tue Mar 21 22:35:17 2006 @@ -0,0 +1,30 @@ +/* Protocol macros */ + +#ifndef _PS2_PROTOCOL_H_ +#define _PS2_PROTOCOL_H_ + +#define BYTE(x) ((unsigned char)(x)) + +#define COMMAND_RESET BYTE(0xFF) +#define COMMAND_RESEND BYTE(0xFE) +#define COMMAND_SET_DEFAULTS BYTE(0xF6) +#define COMMAND_DISABLE_REPORTING BYTE(0xF5) +#define COMMAND_ENABLE_REPORTING BYTE(0xF4) +#define COMMAND_SET_SAMPLE_RATE BYTE(0xF3) +#define COMMAND_GET_DEVICE_ID BYTE(0xF2) +#define COMMAND_GET_DEVICE_ID2 BYTE(0xE1) +#define COMMAND_SET_REMOTE_MODE BYTE(0xF0) +#define COMMAND_SET_WRAP_MODE BYTE(0xEE) +#define COMMAND_RESET_WRAP_MODE BYTE(0xEC) +#define COMMAND_READ_DATA BYTE(0xEB) +#define COMMAND_SET_STREAM_MODE BYTE(0xEA) +#define COMMAND_STATUS_REQUEST BYTE(0xE9) +#define COMMAND_SET_RESOLUTION BYTE(0xE8) +#define COMMAND_SET_MOUSE_SCALING21 BYTE(0xE7) +#define COMMAND_SET_MOUSE_SCALING11 BYTE(0xE6) + +#define RESPONSE_ACK BYTE(0xFA) +#define RESPONSE_ERROR BYTE(0xFC) +#define RESPONSE_POST_OK BYTE(0xAA) + +#endif /* _PS2_PROTOCOL_H_ */ diff -ruN /usr/src.orig/lib/libps2/test/Makefile /usr/src/lib/libps2/test/Makefile --- /usr/src.orig/lib/libps2/test/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/lib/libps2/test/Makefile Sat Nov 26 18:56:25 2005 @@ -0,0 +1,8 @@ + +PROG=test +SRCS=test.c + +CFLAGS+=-I../ -g +LDFLAGS+=-R../ -L../ -lps2 + +.include diff -ruN /usr/src.orig/lib/libps2/test/test.c /usr/src/lib/libps2/test/test.c --- /usr/src.orig/lib/libps2/test/test.c Wed Dec 31 19:00:00 1969 +++ /usr/src/lib/libps2/test/test.c Sat Nov 26 18:56:25 2005 @@ -0,0 +1,106 @@ + +#include +#include +#include "ps2.h" + +static void printbits(char val) { + int i; + for (i = 7; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +int main(int argc, char **argv) { + + char *dev = "/dev/psm0"; + char status[3]; + char data[12]; + int bytes; + fd_set fds; + + if (*(argv + 1) != NULL) + dev = *(argv + 1); + + if (ps2_open(dev) == -1) + exit(1); + + ps2_reset(); + ps2_disable_stream(); + + ps2_ext_command(0); + ps2_get_status(status); + printf("Version: %d.%d\n", status[2] & 0x0F, status[0]); + + ps2_ext_command(1); + ps2_get_status(status); + + printf("0: "), printbits(status[0]), printf("(0x%02x)\n",status[0]); + printf("1: "), printbits(status[1]), printf("(0x%02x)\n",status[1]); + printf("2: "), printbits(status[2]), printf("(0x%02x)\n",status[2]); + //printf("Abs: %d\n", (status[2] & (1 << 7))); + if ((status[2] & (1 << 7)) == 0) { + /* Enable Absolute mode, high packet rate, and Wmode ( 0xC1 ) */ + printf("Absolute mode not set, enabling...\n"); + ps2_ext_command(0xc1); + ps2_set_sample_rate(20); /* 0x14 */ + } else { + printf("Absolute mode set already?\n"); + } + + ps2_ext_command(1); + ps2_get_status(status); + + printf("0: "), printbits(status[0]), printf("(0x%02x)\n",status[0]); + printf("1: "), printbits(status[1]), printf("(0x%02x)\n",status[1]); + printf("2: "), printbits(status[2]), printf("(0x%02x)\n",status[2]); + + if (status[2] & (1 << 7)) + printf("Absolute mode is set correctly (bit 7, byte 3)\n"); + else + printf("ABSOLUTE MODE IS OFF!?\n"); + + ps2_enable_stream(); + + ps2_ext_command(1); + ps2_get_status(status); + + printf("0: "), printbits(status[0]), printf("(0x%02x)\n",status[0]); + printf("1: "), printbits(status[1]), printf("(0x%02x)\n",status[1]); + printf("2: "), printbits(status[2]), printf("(0x%02x)\n",status[2]); + + if (status[2] & (1 << 7)) + printf("Absolute mode is set correctly (bit 7, byte 3)\n"); + else + printf("2: ABSOLUTE MODE IS OFF!?\n"); + + /* Set packetsize to 6 bytes */ + ps2_set_packetsize(6); + + FD_ZERO(&fds); + FD_SET(ps2_mousefd(), &fds); + while (1) { + int x; + int c; + + c = select(FD_SETSIZE, &fds, NULL, NULL, NULL); + if (c >= 0) { + bytes = read(ps2_mousefd(), data, 6); + if (bytes == 6) { + printf("long packet\n"); + for (x = 0; x < bytes; x++) { + printf(" %d: ", x), printbits(data[x]), printf(" (0x%02x)\n", data[x]); + } + } else if (bytes == 3) { + printf("short packet\n"); + //printf("(%d,%d) %d,%d,%d\n", + //data[1] * ((data[0] ^ (1 << 4)) ? -1 : 1), + //data[2] * ((data[0] ^ (1 << 5)) ? -1 : 1), + //data[0] & (1 << 0), + ////data[0] & (1 << 1), + //data[0] & (1 << 2)); + } + } + } + + return 0; +} diff -ruN /usr/src.orig/sys/conf/files.i386 /usr/src/sys/conf/files.i386 --- /usr/src.orig/sys/conf/files.i386 Sun Mar 5 17:52:16 2006 +++ /usr/src/sys/conf/files.i386 Thu Apr 13 15:45:39 2006 @@ -142,6 +142,8 @@ dev/atkbdc/atkbdc_isa.c optional atkbdc isa dev/atkbdc/atkbdc_subr.c optional atkbdc dev/atkbdc/psm.c optional psm atkbdc +dev/atkbdc/newpsm.c optional newpsm atkbdc +dev/atkbdc/psmcpnp.c optional newpsm atkbdc dev/ce/ceddk.c optional ce dev/ce/if_ce.c optional ce dev/ce/tau32-ddk.c optional ce diff -ruN /usr/src.orig/sys/dev/atkbdc/newpsm.c /usr/src/sys/dev/atkbdc/newpsm.c --- /usr/src.orig/sys/dev/atkbdc/newpsm.c Wed Dec 31 19:00:00 1969 +++ /usr/src/sys/dev/atkbdc/newpsm.c Thu Apr 13 20:54:34 2006 @@ -0,0 +1,1577 @@ +/*- + * Copyright (c) 1992, 1993 Erik Forsberg. + * Copyright (c) 1996, 1997 Kazutaka YOKOTA. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Ported to 386bsd Oct 17, 1992 + * Sandi Donno, Computer Science, University of Cape Town, South Africa + * Please send bug reports to sandi@cs.uct.ac.za + * + * Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca - + * although I was only partially successful in getting the alpha release + * of his "driver for the Logitech and ATI Inport Bus mice for use with + * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless + * found his code to be an invaluable reference when porting this driver + * to 386bsd. + * + * Further modifications for latest 386BSD+patchkit and port to NetBSD, + * Andrew Herbert - 8 June 1993 + * + * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by + * Andrew Herbert - 12 June 1993 + * + * Modified for PS/2 mouse by Charles Hannum + * - 13 June 1993 + * + * Modified for PS/2 AUX mouse by Shoji Yuen + * - 24 October 1993 + * + * Hardware access routines and probe logic rewritten by + * Kazutaka Yokota + * - 3, 14, 22 October 1996. + * - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'... + * - 14, 30 November 1996. Uses `kbdio.c'. + * - 13 December 1996. Uses queuing version of `kbdio.c'. + * - January/February 1997. Tweaked probe logic for + * HiNote UltraII/Latitude/Armada laptops. + * - 30 July 1997. Added APM support. + * - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX). + * Improved sync check logic. + * Vendor specific support routines. + */ + +#include +__FBSDID("$FreeBSD: src/sys/dev/atkbdc/psm.c,v 1.86 2005/06/10 20:56:37 marius Exp $"); + +#include "opt_isa.h" +#include "opt_psm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#include +#include + +/* + * Driver specific options: the following options may be set by + * `options' statements in the kernel configuration file. + */ + +/* debugging */ +#ifndef PSM_DEBUG +#define PSM_DEBUG 0 /* + * logging: 0: none, 1: brief, 2: verbose + * 3: sync errors, 4: all packets + */ +#endif +#define VLOG(level, args) \ +do { \ + if (verbose >= level) \ + log args; \ +} while (0) + +#ifndef PSM_INPUT_TIMEOUT +#define PSM_INPUT_TIMEOUT 2000000 /* 2 sec */ +#endif + +/* end of driver specific options */ + +#define PSMCPNP_DRIVER_NAME "psmcpnp" + +/* input queue */ +#define PSM_BUFSIZE 960 +#define PSM_SMALLBUFSIZE 240 + +/* some macros */ +#define PSM_UNIT(dev) (minor(dev) >> 1) +#define PSM_NBLOCKIO(dev) (minor(dev) & 1) +#define PSM_MKMINOR(unit,block) (((unit) << 1) | ((block) ? 0:1)) + +/* ring buffer */ +typedef struct ringbuf { + int count; /* # of valid elements in the buffer */ + int head; /* head pointer */ + int tail; /* tail poiner */ + unsigned char buf[PSM_BUFSIZE]; +} ringbuf_t; + +/* data buffer */ +typedef struct packetbuf { + unsigned char ipacket[16]; /* interim input buffer */ + int inputbytes; /* # of bytes in the input buffer */ +} packetbuf_t; + +#ifndef PSM_PACKETQUEUE +#define PSM_PACKETQUEUE 128 +#endif + +/* driver control block */ +struct psm_softc { /* Driver status information */ + int unit; + struct selinfo rsel; /* Process selecting for Input */ + unsigned char state; /* Mouse driver state */ + int config; /* driver configuration flags */ + int flags; /* other flags */ + KBDC kbdc; /* handle to access the keyboard controller */ + struct resource *intr; /* IRQ resource */ + void *ih; /* interrupt handle */ + ringbuf_t queue; /* mouse status queue */ + packetbuf_t pqueue[PSM_PACKETQUEUE]; /* mouse data queue */ + int pqueue_start; /* start of data in queue */ + int pqueue_end; /* end of data in queue */ + int button; /* the latest button state */ + int syncerrors; /* # of bytes discarded searching for sync */ + int pkterrors; /* # of packets failed during quaranteen. */ + struct timeval inputtimeout; + struct timeval lastsoftintr; /* time of last soft interrupt */ + struct timeval lastinputerr; /* time last sync error happened */ + int watchdog; /* watchdog timer flag */ + struct callout_handle callout; /* watchdog timer call out */ + struct callout_handle softcallout; /* buffer timer call out */ + struct cdev *dev; + struct cdev *bdev; + int lasterr; + int cmdcount; + mousemode_t mode; +}; + +static devclass_t psm_devclass; +#define PSM_SOFTC(unit) ((struct psm_softc*)devclass_get_softc(psm_devclass, unit)) + +/* driver state flags (state) */ +#define PSM_VALID 0x80 +#define PSM_OPEN 1 /* Device is open */ +#define PSM_ASLP 2 /* Waiting for mouse data */ +#define PSM_SOFTARMED 4 /* Software interrupt armed */ +#define PSM_NEED_SYNCBITS 8 /* Set syncbits using next data pkt */ + +/* driver configuration flags (config) */ +#define PSM_CONFIG_RESOLUTION 0x000f /* resolution */ +#define PSM_CONFIG_ACCEL 0x00f0 /* acceleration factor */ +#define PSM_CONFIG_NOCHECKSYNC 0x0100 /* disable sync. test */ +#define PSM_CONFIG_NOIDPROBE 0x0200 /* disable mouse model probe */ +#define PSM_CONFIG_NORESET 0x0400 /* don't reset the mouse */ +#define PSM_CONFIG_FORCETAP 0x0800 /* assume `tap' action exists */ +#define PSM_CONFIG_IGNPORTERROR 0x1000 /* ignore error in aux port test */ +#define PSM_CONFIG_HOOKRESUME 0x2000 /* hook the system resume event */ +#define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */ +#define PSM_CONFIG_SYNCHACK 0x8000 /* enable `out-of-sync' hack */ + +#define PSM_CONFIG_FLAGS (PSM_CONFIG_RESOLUTION \ + | PSM_CONFIG_ACCEL \ + | PSM_CONFIG_NOCHECKSYNC \ + | PSM_CONFIG_SYNCHACK \ + | PSM_CONFIG_NOIDPROBE \ + | PSM_CONFIG_NORESET \ + | PSM_CONFIG_FORCETAP \ + | PSM_CONFIG_IGNPORTERROR \ + | PSM_CONFIG_HOOKRESUME \ + | PSM_CONFIG_INITAFTERSUSPEND) + +/* other flags (flags) */ +#define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */ + +/* Tunables */ +static int verbose = PSM_DEBUG; +TUNABLE_INT("debug.psm.loglevel", &verbose); + +/* function prototypes */ +static void psmidentify(driver_t *, device_t); +static int psmprobe(device_t); +static int psmattach(device_t); +static int psmdetach(device_t); +static int psmresume(device_t); + +static d_open_t psmopen; +static d_close_t psmclose; +static d_read_t psmread; +static d_ioctl_t psmioctl; +static d_poll_t psmpoll; + +static int enable_aux_dev(KBDC); +static int disable_aux_dev(KBDC); +static int get_mouse_status(KBDC, int *, int, int); +static void recover_from_error(KBDC); +static int restore_controller(KBDC, int); +static int doinitialize(struct psm_softc *); +static int doopen(struct psm_softc *, int); +static int reinitialize(struct psm_softc *, int); +static void psmsoftintr(void *); +static void psmintr(void *); +static void psmtimeout(void *); +static int timeelapsed(const struct timeval *, + int, int, const struct timeval *); +static void dropqueue(struct psm_softc *); +static void flushpackets(struct psm_softc *); + +/* device driver declarateion */ +static device_method_t psm_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, psmidentify), + DEVMETHOD(device_probe, psmprobe), + DEVMETHOD(device_attach, psmattach), + DEVMETHOD(device_detach, psmdetach), + DEVMETHOD(device_resume, psmresume), + + { 0, 0 } +}; + +static driver_t psm_driver = { + PSM_DRIVER_NAME, + psm_methods, + sizeof(struct psm_softc), +}; + + +static struct cdevsw psm_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, + .d_open = psmopen, + .d_close = psmclose, + .d_read = psmread, + .d_ioctl = psmioctl, + .d_poll = psmpoll, + .d_name = PSM_DRIVER_NAME, +}; + +/* device I/O routines */ +static int +enable_aux_dev(KBDC kbdc) +{ + int res; + + res = send_aux_command(kbdc, PSMC_ENABLE_DEV); + VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res)); + + return (res == PSM_ACK); +} + +static int +disable_aux_dev(KBDC kbdc) +{ + int res; + + res = send_aux_command(kbdc, PSMC_DISABLE_DEV); + VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res)); + + return (res == PSM_ACK); +} + +static int +get_mouse_status(KBDC kbdc, int *status, int flag, int len) +{ + int cmd; + int res; + int i; + + switch (flag) { + case 0: + default: + cmd = PSMC_SEND_DEV_STATUS; + break; + case 1: + cmd = PSMC_SEND_DEV_DATA; + break; + } + empty_aux_buffer(kbdc, 5); + res = send_aux_command(kbdc, cmd); + VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", + (flag == 1) ? "DATA" : "STATUS", res)); + if (res != PSM_ACK) + return 0; + + for (i = 0; i < len; ++i) { + status[i] = read_aux_data(kbdc); + if (status[i] < 0) + break; + } + + VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n", + (flag == 1) ? "data" : "status", status[0], status[1], status[2])); + + return i; +} + +/* misc subroutines */ + +static void +recover_from_error(KBDC kbdc) +{ + /* discard anything left in the output buffer */ + empty_both_buffers(kbdc, 10); + + /* + * NOTE: somehow diagnostic and keyboard port test commands bring the + * keyboard back. + */ + if (!test_controller(kbdc)) + log(LOG_ERR, "psm: keyboard controller failed.\n"); + /* if there isn't a keyboard in the system, the following error is OK */ + if (test_kbd_port(kbdc) != 0) + VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n")); +} + +static int +restore_controller(KBDC kbdc, int command_byte) +{ + empty_both_buffers(kbdc, 10); + + if (!set_controller_command_byte(kbdc, 0xff, command_byte)) { + log(LOG_ERR, "psm: failed to restore the keyboard controller " + "command byte.\n"); + empty_both_buffers(kbdc, 10); + return FALSE; + } else { + empty_both_buffers(kbdc, 10); + return TRUE; + } +} + +/* + * Re-initialize the aux port and device. The aux port must be enabled + * and its interrupt must be disabled before calling this routine. + * The aux device will be disabled before returning. + * The keyboard controller must be locked via `kbdc_lock()' before + * calling this routine. + */ +static int +doinitialize(struct psm_softc *sc) +{ + KBDC kbdc = sc->kbdc; + int stat[3]; + int i; + + switch((i = test_aux_port(kbdc))) { + case 1: /* ignore these errors */ + case 2: + case 3: + case PSM_ACK: + if (verbose) + log(LOG_DEBUG, "psm%d: strange result for test aux port (%d).\n", + sc->unit, i); + /* FALLTHROUGH */ + case 0: /* no error */ + break; + case -1: /* time out */ + default: /* error */ + recover_from_error(kbdc); + if (sc->config & PSM_CONFIG_IGNPORTERROR) + break; + log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n", + sc->unit, i); + return FALSE; + } + + if (sc->config & PSM_CONFIG_NORESET) { + /* + * Don't try to reset the pointing device. It may possibly be + * left in the unknown state, though... + */ + } else { + /* + * NOTE: some controllers appears to hang the `keyboard' when + * the aux port doesn't exist and `PSMC_RESET_DEV' is issued. + */ + if (!reset_aux_dev(kbdc)) { + recover_from_error(kbdc); + log(LOG_ERR, "psm%d: failed to reset the aux device.\n", sc->unit); + return FALSE; + } + } + + /* + * both the aux port and the aux device is functioning, see + * if the device can be enabled. + */ + if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) { + log(LOG_ERR, "psm%d: failed to enable the aux device.\n", sc->unit); + return FALSE; + } + empty_both_buffers(kbdc, 10); /* remove stray data if any */ + + /* Record sync on the next data packet we see. */ + sc->flags |= PSM_NEED_SYNCBITS; + + /* just check the status of the mouse */ + if (get_mouse_status(kbdc, stat, 0, 3) < 3) + log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n", + sc->unit); + + return TRUE; +} + +static int +doopen(struct psm_softc *sc, int command_byte) +{ + int stat[3]; + + /* enable the mouse device */ + if (!enable_aux_dev(sc->kbdc)) { + /* MOUSE ERROR: failed to enable the mouse because: + * 1) the mouse is faulty, + * 2) the mouse has been removed(!?) + * In the latter case, the keyboard may have hung, and need + * recovery procedure... + */ + recover_from_error(sc->kbdc); + { + restore_controller(sc->kbdc, command_byte); + /* mark this device is no longer available */ + sc->state &= ~PSM_VALID; + log(LOG_ERR, "psm%d: failed to enable the device (doopen).\n", + sc->unit); + return (EIO); + } + } + + if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) + log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n", sc->unit); + + /* enable the aux port and interrupt */ + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + (command_byte & KBD_KBD_CONTROL_BITS) + | KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) { + /* CONTROLLER ERROR */ + disable_aux_dev(sc->kbdc); + restore_controller(sc->kbdc, command_byte); + log(LOG_ERR, "psm%d: failed to enable the aux interrupt (doopen).\n", + sc->unit); + return (EIO); + } + + /* start the watchdog timer */ + sc->watchdog = FALSE; + sc->callout = timeout(psmtimeout, (void *)(uintptr_t)sc, hz*2); + + return (0); +} + +static int +reinitialize(struct psm_softc *sc, int doinit) +{ + int err; + int c; + int s; + + /* don't let anybody mess with the aux device */ + if (!kbdc_lock(sc->kbdc, TRUE)) + return (EIO); + s = spltty(); + + /* block our watchdog timer */ + sc->watchdog = FALSE; + untimeout(psmtimeout, (void *)(uintptr_t)sc, sc->callout); + callout_handle_init(&sc->callout); + + /* save the current controller command byte */ + empty_both_buffers(sc->kbdc, 10); + c = get_controller_command_byte(sc->kbdc); + VLOG(2, (LOG_DEBUG, "psm%d: current command byte: %04x (reinitialize).\n", + sc->unit, c)); + + /* enable the aux port but disable the aux interrupt and the keyboard */ + if ((c == -1) || !set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* CONTROLLER ERROR */ + splx(s); + kbdc_lock(sc->kbdc, FALSE); + log(LOG_ERR, "psm%d: unable to set the command byte (reinitialize).\n", + sc->unit); + return (EIO); + } + + /* flush any data */ + if (sc->state & PSM_VALID) { + disable_aux_dev(sc->kbdc); /* this may fail; but never mind... */ + empty_aux_buffer(sc->kbdc, 10); + } + flushpackets(sc); + sc->syncerrors = 0; + sc->pkterrors = 0; + memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr)); + + /* try to detect the aux device; are you still there? */ + err = 0; + if (doinit) { + if (doinitialize(sc)) { + /* yes */ + sc->state |= PSM_VALID; + } else { + /* the device has gone! */ + restore_controller(sc->kbdc, c); + sc->state &= ~PSM_VALID; + log(LOG_ERR, "psm%d: the aux device has gone! (reinitialize).\n", + sc->unit); + err = ENXIO; + } + } + splx(s); + + /* restore the driver state */ + if ((sc->state & PSM_OPEN) && (err == 0)) { + /* enable the aux device and the port again */ + err = doopen(sc, c); + if (err != 0) + log(LOG_ERR, "psm%d: failed to enable the device (reinitialize).\n", + sc->unit); + } else { + /* restore the keyboard port and disable the aux port */ + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + (c & KBD_KBD_CONTROL_BITS) + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* CONTROLLER ERROR */ + log(LOG_ERR, + "psm%d: failed to disable the aux port (reinitialize).\n", + sc->unit); + err = EIO; + } + } + + kbdc_lock(sc->kbdc, FALSE); + return (err); +} + +/* psm driver entry points */ + +static void +psmidentify(driver_t *driver, device_t parent) +{ + device_t psmc; + device_t psm; + u_long irq; + int unit; + + unit = device_get_unit(parent); + + /* always add at least one child */ + psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit); + if (psm == NULL) + return; + + irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX); + if (irq > 0) + return; + + /* + * If the PS/2 mouse device has already been reported by ACPI or + * PnP BIOS, obtain the IRQ resource from it. + * (See psmcpnp_attach() below.) + */ + psmc = device_find_child(device_get_parent(parent), + PSMCPNP_DRIVER_NAME, unit); + if (psmc == NULL) + return; + irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0); + if (irq <= 0) + return; + bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1); +} + +#define endprobe(v) do { if (bootverbose) \ + --verbose; \ + kbdc_set_device_mask(sc->kbdc, mask); \ + kbdc_lock(sc->kbdc, FALSE); \ + return (v); \ + } while (0) + +static int +psmprobe(device_t dev) +{ + int unit = device_get_unit(dev); + struct psm_softc *sc = device_get_softc(dev); + int stat[3]; + int command_byte; + int mask; + int rid; + int i; + +#if 0 + kbdc_debug(TRUE); +#endif + + /* see if IRQ is available */ + rid = KBDC_RID_AUX; + sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (sc->intr == NULL) { + if (bootverbose) + device_printf(dev, "unable to allocate IRQ\n"); + return (ENXIO); + } + bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); + + sc->unit = unit; + sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev))); + sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS; + /* XXX: for backward compatibility */ +#if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM) + sc->config |= +#ifdef PSM_RESETAFTERSUSPEND + PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND; +#else + PSM_CONFIG_HOOKRESUME; +#endif +#endif /* PSM_HOOKRESUME | PSM_HOOKAPM */ + sc->flags = 0; + if (bootverbose) + ++verbose; + + device_set_desc(dev, "(new) PS/2 Mouse"); + + if (!kbdc_lock(sc->kbdc, TRUE)) { + printf("psm%d: unable to lock the controller.\n", unit); + if (bootverbose) + --verbose; + return (ENXIO); + } + + /* + * NOTE: two bits in the command byte controls the operation of the + * aux port (mouse port): the aux port disable bit (bit 5) and the aux + * port interrupt (IRQ 12) enable bit (bit 2). + */ + + /* discard anything left after the keyboard initialization */ + empty_both_buffers(sc->kbdc, 10); + + /* save the current command byte; it will be used later */ + mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS; + command_byte = get_controller_command_byte(sc->kbdc); + if (verbose) + printf("psm%d: current command byte:%04x\n", unit, command_byte); + if (command_byte == -1) { + /* CONTROLLER ERROR */ + printf("psm%d: unable to get the current command byte value.\n", + unit); + endprobe(ENXIO); + } + + /* + * disable the keyboard port while probing the aux port, which must be + * enabled during this routine + */ + if (!set_controller_command_byte(sc->kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* + * this is CONTROLLER ERROR; I don't know how to recover + * from this error... + */ + restore_controller(sc->kbdc, command_byte); + printf("psm%d: unable to set the command byte.\n", unit); + endprobe(ENXIO); + } + write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT); + + /* + * NOTE: `test_aux_port()' is designed to return with zero if the aux + * port exists and is functioning. However, some controllers appears + * to respond with zero even when the aux port doesn't exist. (It may + * be that this is only the case when the controller DOES have the aux + * port but the port is not wired on the motherboard.) The keyboard + * controllers without the port, such as the original AT, are + * supporsed to return with an error code or simply time out. In any + * case, we have to continue probing the port even when the controller + * passes this test. + * + * XXX: some controllers erroneously return the error code 1, 2 or 3 + * when it has the perfectly functional aux port. We have to ignore + * this error code. Even if the controller HAS error with the aux + * port, it will be detected later... + * XXX: another incompatible controller returns PSM_ACK (0xfa)... + */ + switch ((i = test_aux_port(sc->kbdc))) { + case 1: /* ignore these errors */ + case 2: + case 3: + case PSM_ACK: + if (verbose) + printf("psm%d: strange result for test aux port (%d).\n", + unit, i); + /* FALLTHROUGH */ + case 0: /* no error */ + break; + case -1: /* time out */ + default: /* error */ + recover_from_error(sc->kbdc); + if (sc->config & PSM_CONFIG_IGNPORTERROR) + break; + restore_controller(sc->kbdc, command_byte); + if (verbose) + printf("psm%d: the aux port is not functioning (%d).\n", + unit, i); + endprobe(ENXIO); + } + + if (sc->config & PSM_CONFIG_NORESET) { + /* + * Don't try to reset the pointing device. It may possibly be + * left in the unknown state, though... + */ + } else { + /* + * NOTE: some controllers appears to hang the `keyboard' when the aux + * port doesn't exist and `PSMC_RESET_DEV' is issued. + * + * Attempt to reset the controller twice -- this helps + * pierce through some KVM switches. The second reset + * is non-fatal. + */ + if (!reset_aux_dev(sc->kbdc)) { + recover_from_error(sc->kbdc); + restore_controller(sc->kbdc, command_byte); + if (verbose) + printf("psm%d: failed to reset the aux device.\n", unit); + endprobe(ENXIO); + } else if (!reset_aux_dev(sc->kbdc)) { + recover_from_error(sc->kbdc); + if (verbose >= 2) + printf("psm%d: failed to reset the aux device (2).\n", + unit); + } + } + + /* + * both the aux port and the aux device is functioning, see if the + * device can be enabled. NOTE: when enabled, the device will start + * sending data; we shall immediately disable the device once we know + * the device can be enabled. + */ + if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) { + /* MOUSE ERROR */ + recover_from_error(sc->kbdc); + restore_controller(sc->kbdc, command_byte); + if (verbose) + printf("psm%d: failed to enable the aux device.\n", unit); + endprobe(ENXIO); + } + + /* Record sync on the next data packet we see. */ + sc->flags |= PSM_NEED_SYNCBITS; + + /* just check the status of the mouse */ + /* + * NOTE: XXX there are some arcane controller/mouse combinations out + * there, which hung the controller unless there is data transmission + * after ACK from the mouse. + */ + if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) { + printf("psm%d: failed to get status.\n", unit); + } + + /* disable the aux port for now... */ + if (!set_controller_command_byte(sc->kbdc, + KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, + (command_byte & KBD_KBD_CONTROL_BITS) + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* + * this is CONTROLLER ERROR; I don't know the proper way to + * recover from this error... + */ + restore_controller(sc->kbdc, command_byte); + printf("psm%d: unable to set the command byte.\n", unit); + endprobe(ENXIO); + } + + /* done */ + kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS); + kbdc_lock(sc->kbdc, FALSE); + return (0); +} + +static int +psmattach(device_t dev) +{ + int unit = device_get_unit(dev); + struct psm_softc *sc = device_get_softc(dev); + int error; + int rid; + + /* Setup initial state */ + sc->state = PSM_VALID; + callout_handle_init(&sc->callout); + + /* Setup our interrupt handler */ + rid = KBDC_RID_AUX; + sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (sc->intr == NULL) + return (ENXIO); + error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, psmintr, sc, &sc->ih); + if (error) { + bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); + return (error); + } + + /* Done */ + sc->dev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, FALSE), 0, 0, 0666, + "psm%d", unit); + sc->bdev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, TRUE), 0, 0, 0666, + "bpsm%d", unit); + + printf("psm%d: attached\n", unit); + + if (bootverbose) + --verbose; + + return (0); +} + +static int +psmdetach(device_t dev) +{ + struct psm_softc *sc; + int rid; + + sc = device_get_softc(dev); + if (sc->state & PSM_OPEN) + return EBUSY; + + rid = KBDC_RID_AUX; + bus_teardown_intr(dev, sc->intr, sc->ih); + bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); + + destroy_dev(sc->dev); + destroy_dev(sc->bdev); + + return 0; +} + +static int +psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) +{ + int unit = PSM_UNIT(dev); + struct psm_softc *sc; + int command_byte; + int err; + int s; + + /* Get device data */ + sc = PSM_SOFTC(unit); + if ((sc == NULL) || (sc->state & PSM_VALID) == 0) + /* the device is no longer valid/functioning */ + return (ENXIO); + + /* Disallow multiple opens */ + if (sc->state & PSM_OPEN) + return (EBUSY); + + device_busy(devclass_get_device(psm_devclass, unit)); + + /* Initialize state */ + sc->watchdog = FALSE; + + /* flush the event queue */ + sc->queue.count = 0; + sc->queue.head = 0; + sc->queue.tail = 0; + sc->button = 0; + sc->pqueue_start = 0; + sc->pqueue_end = 0; + + /* empty input buffer */ + flushpackets(sc); + sc->syncerrors = 0; + sc->pkterrors = 0; + + /* don't let timeout routines in the keyboard driver to poll the kbdc */ + if (!kbdc_lock(sc->kbdc, TRUE)) + return (EIO); + + /* save the current controller command byte */ + s = spltty(); + command_byte = get_controller_command_byte(sc->kbdc); + + /* enable the aux port and temporalily disable the keyboard */ + if ((command_byte == -1) + || !set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* CONTROLLER ERROR; do you know how to get out of this? */ + kbdc_lock(sc->kbdc, FALSE); + splx(s); + log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n", + unit); + return (EIO); + } + /* + * Now that the keyboard controller is told not to generate + * the keyboard and mouse interrupts, call `splx()' to allow + * the other tty interrupts. The clock interrupt may also occur, + * but timeout routines will be blocked by the poll flag set + * via `kbdc_lock()' + */ + splx(s); + + /* enable the mouse device */ + err = doopen(sc, command_byte); + + /* done */ + if (err == 0) + sc->state |= PSM_OPEN; + kbdc_lock(sc->kbdc, FALSE); + return (err); +} + +static int +psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) +{ + int unit = PSM_UNIT(dev); + struct psm_softc *sc = PSM_SOFTC(unit); + int stat[3]; + int command_byte; + int s; + + /* don't let timeout routines in the keyboard driver to poll the kbdc */ + if (!kbdc_lock(sc->kbdc, TRUE)) + return (EIO); + + /* save the current controller command byte */ + s = spltty(); + command_byte = get_controller_command_byte(sc->kbdc); + if (command_byte == -1) { + kbdc_lock(sc->kbdc, FALSE); + splx(s); + return (EIO); + } + + /* disable the aux interrupt and temporalily disable the keyboard */ + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n", + unit); + /* CONTROLLER ERROR; + * NOTE: we shall force our way through. Because the only + * ill effect we shall see is that we may not be able + * to read ACK from the mouse, and it doesn't matter much + * so long as the mouse will accept the DISABLE command. + */ + } + splx(s); + + /* stop the watchdog timer */ + untimeout(psmtimeout, (void *)(uintptr_t)sc, sc->callout); + callout_handle_init(&sc->callout); + + /* remove anything left in the output buffer */ + empty_aux_buffer(sc->kbdc, 10); + + /* disable the aux device, port and interrupt */ + if (sc->state & PSM_VALID) { + if (!disable_aux_dev(sc->kbdc)) { + /* MOUSE ERROR; + * NOTE: we don't return error and continue, pretending + * we have successfully disabled the device. It's OK because + * the interrupt routine will discard any data from the mouse + * hereafter. + */ + log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n", + unit); + } + + if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) + log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", unit); + } + + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + (command_byte & KBD_KBD_CONTROL_BITS) + | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* CONTROLLER ERROR; + * we shall ignore this error; see the above comment. + */ + log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n", + unit); + } + + /* remove anything left in the output buffer */ + empty_aux_buffer(sc->kbdc, 10); + + /* close is almost always successful */ + sc->state &= ~PSM_OPEN; + kbdc_lock(sc->kbdc, FALSE); + device_unbusy(devclass_get_device(psm_devclass, unit)); + return (0); +} + +static int +psmread(struct cdev *dev, struct uio *uio, int flag) +{ + register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); + unsigned char buf[PSM_SMALLBUFSIZE]; + int error = 0; + int s; + int l; + + if ((sc->state & PSM_VALID) == 0) + return EIO; + + /* block until mouse activity occured */ + s = spltty(); + while (sc->queue.count <= 0) { + if (PSM_NBLOCKIO(dev)) { + splx(s); + return EWOULDBLOCK; + } + sc->state |= PSM_ASLP; + error = tsleep( sc, PZERO | PCATCH, "psmrea", 0); + sc->state &= ~PSM_ASLP; + if (error) { + splx(s); + return error; + } else if ((sc->state & PSM_VALID) == 0) { + /* the device disappeared! */ + splx(s); + return EIO; + } + } + splx(s); + + /* copy data to the user land */ + while ((sc->queue.count > 0) && (uio->uio_resid > 0)) { + s = spltty(); + l = imin(sc->queue.count, uio->uio_resid); + if (l > sizeof(buf)) + l = sizeof(buf); + if (l > sizeof(sc->queue.buf) - sc->queue.head) { + bcopy(&sc->queue.buf[sc->queue.head], &buf[0], + sizeof(sc->queue.buf) - sc->queue.head); + bcopy(&sc->queue.buf[0], + &buf[sizeof(sc->queue.buf) - sc->queue.head], + l - (sizeof(sc->queue.buf) - sc->queue.head)); + } else { + bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l); + } + sc->queue.count -= l; + sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf); + splx(s); + error = uiomove(buf, l, uio); + if (error) + break; + } + + return error; +} + +static int +block_mouse_data(struct psm_softc *sc, int *c) +{ + int s; + + if (!kbdc_lock(sc->kbdc, TRUE)) + return EIO; + + s = spltty(); + *c = get_controller_command_byte(sc->kbdc); + if ((*c == -1) + || !set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT + | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { + /* this is CONTROLLER ERROR */ + splx(s); + kbdc_lock(sc->kbdc, FALSE); + return EIO; + } + + /* + * The device may be in the middle of status data transmission. + * The transmission will be interrupted, thus, incomplete status + * data must be discarded. Although the aux interrupt is disabled + * at the keyboard controller level, at most one aux interrupt + * may have already been pending and a data byte is in the + * output buffer; throw it away. Note that the second argument + * to `empty_aux_buffer()' is zero, so that the call will just + * flush the internal queue. + * `psmintr()' will be invoked after `splx()' if an interrupt is + * pending; it will see no data and returns immediately. + */ + empty_aux_buffer(sc->kbdc, 0); /* flush the queue */ + read_aux_data_no_wait(sc->kbdc); /* throw away data if any */ + flushpackets(sc); + splx(s); + + return 0; +} + +static void +dropqueue(struct psm_softc *sc) +{ + + sc->queue.count = 0; + sc->queue.head = 0; + sc->queue.tail = 0; + if ((sc->state & PSM_SOFTARMED) != 0) { + sc->state &= ~PSM_SOFTARMED; + untimeout(psmsoftintr, (void *)(uintptr_t)sc, sc->softcallout); + } + sc->pqueue_start = sc->pqueue_end; +} + +static void +flushpackets(struct psm_softc *sc) +{ + + dropqueue(sc); + bzero(&sc->pqueue, sizeof(sc->pqueue)); +} + +static int +unblock_mouse_data(struct psm_softc *sc, int c) +{ + int error = 0; + + /* + * We may have seen a part of status data during `set_mouse_XXX()'. + * they have been queued; flush it. + */ + empty_aux_buffer(sc->kbdc, 0); + + /* restore ports and interrupt */ + if (!set_controller_command_byte(sc->kbdc, + kbdc_get_device_mask(sc->kbdc), + c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { + /* CONTROLLER ERROR; this is serious, we may have + * been left with the inaccessible keyboard and + * the disabled mouse interrupt. + */ + error = EIO; + } + + kbdc_lock(sc->kbdc, FALSE); + return error; +} + +static int +psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) +{ + struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); + int command_byte; + int error = 0; + int s; + + /* Perform IOCTL command */ + switch (cmd) { + case MOUSE_COMMAND: + s = spltty(); + error = block_mouse_data(sc, &command_byte); + if (error) { + uprintf("Error: %d\n", error); + return error; + } + + if (((mousecommand_t *)addr)->data >= 0) { + int res; + res = send_aux_command_and_data(sc->kbdc, + ((mousecommand_t *)addr)->command, + ((mousecommand_t *)addr)->data); + } else { + int res; + res = send_aux_command(sc->kbdc, ((mousecommand_t *)addr)->command); + } + + DELAY(5000); + + { /* XXX: This should be more cleanly written. Move 'x' decl up top? */ + int x = 0; + for (x = 0; x < ((mousecommand_t *)addr)->responselen; x++) { + ((mousecommand_t *)addr)->response[x] = (char)read_aux_data(sc->kbdc); + } + } + + unblock_mouse_data(sc, command_byte); + splx(s); + break; + + case MOUSE_SET_PACKETSIZE: + s = spltty(); + sc->mode.packetsize = *(int *)addr; + splx(s); + break; + + case MOUSE_GET_PACKETSIZE: + s = spltty(); + *(int *)addr = sc->mode.packetsize; + splx(s); + break; + + case MOUSE_SET_SYNCMASK: + s = spltty(); + /* XXX: syncmask is an array becuase ums(4) wants it that way, for now */ + sc->mode.syncmask[0] = *(unsigned char *)addr; + sc->flags |= PSM_NEED_SYNCBITS; + /* XXX: Print this if in debug mode? */ + /* uprintf("New syncmask: %02x\n", sc->mode.syncmask[0]); */ + splx(s); + break; + + case MOUSE_GET_SYNCMASK: + s = spltty(); + /* XXX: ums likes syncmask to be an array */ + *(unsigned char *)addr = sc->mode.syncmask[0]; + splx(s); + break; + + case MOUSE_SET_SYNCBITS: + s = spltty(); + sc->mode.syncbits = *(unsigned char *)addr; + splx(s); + break; + + case MOUSE_GET_SYNCBITS: + s = spltty(); + *(unsigned char *)addr = sc->mode.syncbits; + splx(s); + break; + + default: + return ENOTTY; + } + + return error; +} + +static void +psmtimeout(void *arg) +{ + struct psm_softc *sc; + int s; + + sc = (struct psm_softc *)arg; + s = spltty(); + if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) { + VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit)); + psmintr(sc); + kbdc_lock(sc->kbdc, FALSE); + } + sc->watchdog = TRUE; + splx(s); + sc->callout = timeout(psmtimeout, (void *)(uintptr_t)sc, hz); +} + +/* Add all sysctls under the debug.psm and hw.psm nodes */ +SYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse"); +SYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse"); + +SYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0, ""); + +static int psmhz = 20; +SYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0, ""); +static int psmerrsecs = 2; +SYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0, ""); +static int psmerrusecs = 0; +SYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0, ""); +static int psmsecs = 0; +SYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0, ""); +static int psmusecs = 500000; +SYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0, ""); +static int pkterrthresh = 2; +SYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0, ""); + +//static int tap_threshold = PSM_TAP_THRESHOLD; +//SYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0, ""); +//static int tap_timeout = PSM_TAP_TIMEOUT; +//SYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0, ""); + +static void +psmintr(void *arg) +{ + struct psm_softc *sc = arg; + struct timeval now; + int c; + packetbuf_t *pb; + + /* read until there is nothing to read */ + while((c = read_aux_data_no_wait(sc->kbdc)) != -1) { + + //printf("Got data: %02x\n", c); + pb = &sc->pqueue[sc->pqueue_end]; + /* discard the byte if the device is not open */ + if ((sc->state & PSM_OPEN) == 0) + continue; + + getmicrouptime(&now); + if ((pb->inputbytes > 0) && timevalcmp(&now, &sc->inputtimeout, >)) { + VLOG(3, (LOG_DEBUG, "psmintr: delay too long; " + "resetting byte count\n")); + pb->inputbytes = 0; + sc->syncerrors = 0; + sc->pkterrors = 0; + } + sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT/1000000; + sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT%1000000; + timevaladd(&sc->inputtimeout, &now); + + pb->ipacket[pb->inputbytes++] = c; + if (pb->inputbytes < sc->mode.packetsize) + continue; + + VLOG(4, (LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n", + pb->ipacket[0], pb->ipacket[1], pb->ipacket[2], + pb->ipacket[3], pb->ipacket[4], pb->ipacket[5])); + + c = pb->ipacket[0]; + + if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { + /* XXX: syncmask is an array becuase ums(4) wants it that way, for now */ + sc->mode.syncbits = (c & sc->mode.syncmask[0]); + sc->flags &= ~PSM_NEED_SYNCBITS; + /* XXX: syncmask is an array becuase ums(4) wants it that way, for now */ + VLOG(2, (LOG_DEBUG, "psmintr: Sync bytes now %04x,%04x [%02x]\n", + sc->mode.syncmask[0], sc->mode.syncbits, c)); + + /* XXX: syncmask is an array becuase ums(4) wants it that way, for now */ + } else if ((c & sc->mode.syncmask[0]) != sc->mode.syncbits) { + /* XXX: syncmask is an array becuase ums(4) wants it that way, for now */ + VLOG(3, (LOG_DEBUG, "psmintr: out of sync (%04x != %04x) %d" + " cmds since last error.\n", + c & sc->mode.syncmask[0], sc->mode.syncbits, + sc->cmdcount - sc->lasterr)); + sc->lasterr = sc->cmdcount; + /* + * The sync byte test is a weak measure of packet + * validity. Conservatively discard any input yet + * to be seen by userland when we detect a sync + * error since there is a good chance some of + * the queued packets have undetected errors. + */ + dropqueue(sc); + if (sc->syncerrors == 0) + sc->pkterrors++; + ++sc->syncerrors; + sc->lastinputerr = now; + if (sc->syncerrors >= sc->mode.packetsize * 2 || + sc->pkterrors >= pkterrthresh) { + + /* + * If we've failed to find a single sync byte in 2 + * packets worth of data, or we've seen persistent + * packet errors during the validation period, + * reinitialize the mouse in hopes of returning it + * to the expected mode. + */ + VLOG(3, (LOG_DEBUG, "psmintr: reset the mouse.\n")); + reinitialize(sc, TRUE); + } else if (sc->syncerrors == sc->mode.packetsize) { + + /* + * Try a soft reset after searching for a sync + * byte through a packet length of bytes. + */ + VLOG(3, (LOG_DEBUG, "psmintr: re-enable the mouse.\n")); + pb->inputbytes = 0; + disable_aux_dev(sc->kbdc); + enable_aux_dev(sc->kbdc); + } else { + VLOG(3, (LOG_DEBUG, "psmintr: discard a byte (%d)\n", + sc->syncerrors)); + pb->inputbytes--; + bcopy(&pb->ipacket[1], &pb->ipacket[0], pb->inputbytes); + } + continue; + } + + /* + * We have what appears to be a valid packet. + * Reset the error counters. + */ + sc->syncerrors = 0; + + /* + * Drop even good packets if they occur within a timeout + * period of a sync error. This allows the detection of + * a change in the mouse's packet mode without exposing + * erratic mouse behavior to the user. Some KVMs forget + * enhanced mouse modes during switch events. + */ + if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs, &now)) { + pb->inputbytes = 0; + continue; + } + + /* + * Now that we're out of the validation period, reset + * the packet error count. + */ + sc->pkterrors = 0; + + sc->cmdcount++; + if (++sc->pqueue_end >= PSM_PACKETQUEUE) + sc->pqueue_end = 0; + /* + * If we've filled the queue then call the softintr ourselves, + * otherwise schedule the interrupt for later. + */ + if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) || + (sc->pqueue_end == sc->pqueue_start)) { + if ((sc->state & PSM_SOFTARMED) != 0) { + sc->state &= ~PSM_SOFTARMED; + untimeout(psmsoftintr, arg, sc->softcallout); + } + psmsoftintr(arg); + } else if ((sc->state & PSM_SOFTARMED) == 0) { + sc->state |= PSM_SOFTARMED; + sc->softcallout = timeout(psmsoftintr, arg, + psmhz < 1 ? 1 : (hz/psmhz)); + } + } +} + +static void +psmsoftintr(void *arg) +{ + register struct psm_softc *sc = arg; + int l; + int s; + packetbuf_t *pb; + + getmicrouptime(&sc->lastsoftintr); + + s = spltty(); + + do { + + pb = &sc->pqueue[sc->pqueue_start]; + + /* queue data */ + if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) { + l = imin(pb->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail); + bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l); + if (pb->inputbytes > l) + bcopy(&pb->ipacket[l], &sc->queue.buf[0], pb->inputbytes - l); + sc->queue.tail = + (sc->queue.tail + pb->inputbytes) % sizeof(sc->queue.buf); + sc->queue.count += pb->inputbytes; + } + pb->inputbytes = 0; + + if (++sc->pqueue_start >= PSM_PACKETQUEUE) + sc->pqueue_start = 0; + } while (sc->pqueue_start != sc->pqueue_end); + + if (sc->state & PSM_ASLP) { + sc->state &= ~PSM_ASLP; + wakeup( sc); + } + selwakeuppri(&sc->rsel, PZERO); + sc->state &= ~PSM_SOFTARMED; + splx(s); +} + +static int +psmpoll(struct cdev *dev, int events, struct thread *td) +{ + struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); + int s; + int revents = 0; + + /* Return true if a mouse event available */ + s = spltty(); + if (events & (POLLIN | POLLRDNORM)) { + if (sc->queue.count > 0) + revents |= events & (POLLIN | POLLRDNORM); + else + selrecord(td, &sc->rsel); + } + splx(s); + + return (revents); +} + +/* + * Return true if 'now' is earlier than (start + (secs.usecs)). + * Now may be NULL and the function will fetch the current time from + * getmicrouptime(), or a cached 'now' can be passed in. + * All values should be numbers derived from getmicrouptime(). + */ +static int +timeelapsed(start, secs, usecs, now) + const struct timeval *start, *now; + int secs, usecs; +{ + struct timeval snow, tv; + + /* if there is no 'now' passed in, the get it as a convience. */ + if (now == NULL) { + getmicrouptime(&snow); + now = &snow; + } + + tv.tv_sec = secs; + tv.tv_usec = usecs; + timevaladd(&tv, start); + return (timevalcmp(&tv, now, <)); +} + +static int +psmresume(device_t dev) +{ + struct psm_softc *sc = device_get_softc(dev); + int unit = device_get_unit(dev); + int err; + + VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit)); + + if (!(sc->config & PSM_CONFIG_HOOKRESUME)) + return (0); + + err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND); + + if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) { + /* + * Release the blocked process; it must be notified that the device + * cannot be accessed anymore. + */ + sc->state &= ~PSM_ASLP; + wakeup(sc); + } + + VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit)); + + return (err); +} + +DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0); diff -ruN /usr/src.orig/sys/dev/atkbdc/psmcpnp.c /usr/src/sys/dev/atkbdc/psmcpnp.c --- /usr/src.orig/sys/dev/atkbdc/psmcpnp.c Wed Dec 31 19:00:00 1969 +++ /usr/src/sys/dev/atkbdc/psmcpnp.c Thu Apr 13 20:54:34 2006 @@ -0,0 +1,164 @@ +#include + +#include "opt_isa.h" +#include "opt_psm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#define PSMCPNP_DRIVER_NAME "psmcpnp" + +/* + * This sucks up assignments from PNPBIOS and ACPI. + */ + +/* + * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may + * appear BEFORE the AT keyboard controller. As the PS/2 mouse device + * can be probed and attached only after the AT keyboard controller is + * attached, we shall quietly reserve the IRQ resource for later use. + * If the PS/2 mouse device is reported to us AFTER the keyboard controller, + * copy the IRQ resource to the PS/2 mouse device instance hanging + * under the keyboard controller, then probe and attach it. + */ + +static devclass_t psmcpnp_devclass; + +static device_probe_t psmcpnp_probe; +static device_attach_t psmcpnp_attach; + +static device_method_t psmcpnp_methods[] = { + DEVMETHOD(device_probe, psmcpnp_probe), + DEVMETHOD(device_attach, psmcpnp_attach), + + { 0, 0 } +}; + +static driver_t psmcpnp_driver = { + PSMCPNP_DRIVER_NAME, + psmcpnp_methods, + 1, /* no softc */ +}; + +static struct isa_pnp_id psmcpnp_ids[] = { + { 0x030fd041, "PS/2 mouse port" }, /* PNP0F03 */ + { 0x130fd041, "PS/2 mouse port" }, /* PNP0F13 */ + { 0x1303d041, "PS/2 port" }, /* PNP0313, XXX */ + { 0x02002e4f, "Dell PS/2 mouse port" }, /* Lat. X200, Dell */ + { 0x80374d24, "IBM PS/2 mouse port" }, /* IBM3780, ThinkPad */ + { 0x81374d24, "IBM PS/2 mouse port" }, /* IBM3781, ThinkPad */ + { 0x0190d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9001, Vaio */ + { 0x0290d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9002, Vaio */ + { 0x0390d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9003, Vaio */ + { 0x0490d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9004, Vaio */ + { 0 } +}; + +static int +create_a_copy(device_t atkbdc, device_t me) +{ + device_t psm; + u_long irq; + + /* find the PS/2 mouse device instance under the keyboard controller */ + psm = device_find_child(atkbdc, PSM_DRIVER_NAME, + device_get_unit(atkbdc)); + if (psm == NULL) + return ENXIO; + if (device_get_state(psm) != DS_NOTPRESENT) + return 0; + + /* move our resource to the found device */ + irq = bus_get_resource_start(me, SYS_RES_IRQ, 0); + bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1); + + /* ...then probe and attach it */ + return device_probe_and_attach(psm); +} + +static int +psmcpnp_probe(device_t dev) +{ + struct resource *res; + u_long irq; + int rid; + + if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids)) + return ENXIO; + + /* + * The PnP BIOS and ACPI are supposed to assign an IRQ (12) + * to the PS/2 mouse device node. But, some buggy PnP BIOS + * declares the PS/2 mouse device node without an IRQ resource! + * If this happens, we shall refer to device hints. + * If we still don't find it there, use a hardcoded value... XXX + */ + rid = 0; + irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid); + if (irq <= 0) { + if (resource_long_value(PSM_DRIVER_NAME, + device_get_unit(dev), "irq", &irq) != 0) + irq = 12; /* XXX */ + device_printf(dev, "irq resource info is missing; " + "assuming irq %ld\n", irq); + bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1); + } + res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE); + bus_release_resource(dev, SYS_RES_IRQ, rid, res); + + /* keep quiet */ + if (!bootverbose) + device_quiet(dev); + + return ((res == NULL) ? ENXIO : 0); +} + +static int +psmcpnp_attach(device_t dev) +{ + device_t atkbdc; + int rid; + + /* find the keyboard controller, which may be on acpi* or isa* bus */ + atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME), + device_get_unit(dev)); + if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED)) { + create_a_copy(atkbdc, dev); + } else { + /* + * If we don't have the AT keyboard controller yet, + * just reserve the IRQ for later use... + * (See psmidentify() above.) + */ + rid = 0; + bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE); + } + + return 0; +} + +DRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0); +DRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0); diff -ruN /usr/src.orig/sys/sys/mouse.h /usr/src/sys/sys/mouse.h --- /usr/src.orig/sys/sys/mouse.h Sat Dec 3 21:12:43 2005 +++ /usr/src/sys/sys/mouse.h Thu Apr 13 20:54:34 2006 @@ -20,7 +20,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/sys/mouse.h,v 1.24 2005/12/04 02:12:43 ru Exp $ + * $FreeBSD: src/sys/sys/mouse.h,v 1.23 2005/04/13 07:25:45 mdodd Exp $ */ #ifndef _SYS_MOUSE_H_ @@ -29,6 +29,28 @@ #include #include +/* new psm(4) ioctls */ +#define MOUSE_COMMAND _IOWR('M', 101, mousecommand_t) +#define MOUSE_GET_PACKETSIZE _IOR('M', 102, int) +#define MOUSE_SET_PACKETSIZE _IOW('M', 103, int) +#define MOUSE_GET_SYNCMASK _IOR('M', 104, unsigned char) +#define MOUSE_SET_SYNCMASK _IOW('M', 105, unsigned char) +#define MOUSE_GET_SYNCBITS _IOR('M', 106, unsigned char) +#define MOUSE_SET_SYNCBITS _IOW('M', 107, unsigned char) + +typedef struct mousecommand { + int command; + char data; + char *response; + int responselen; +} mousecommand_t; + +/*** + * + * Below here are the contents of the old /sys/sys/mouse.h + * + ***/ + /* ioctls */ #define MOUSE_GETSTATUS _IOR('M', 0, mousestatus_t) #define MOUSE_GETHWINFO _IOR('M', 1, mousehw_t) @@ -150,6 +172,9 @@ int level; /* driver operation level */ int packetsize; /* the length of the data packet */ unsigned char syncmask[2]; /* sync. data bits in the header byte */ + + /* newer psm(4) wants this (jls) */ + unsigned char syncbits; } mousemode_t; /* protocol */ diff -ruN /usr/src.orig/usr.sbin/Makefile /usr/src/usr.sbin/Makefile --- /usr/src.orig/usr.sbin/Makefile Wed Apr 12 15:52:34 2006 +++ /usr/src/usr.sbin/Makefile Thu Apr 13 15:14:55 2006 @@ -92,7 +92,7 @@ ${_mount_nwfs} \ mount_portalfs \ ${_mount_smbfs} \ - moused \ + ${_moused} \ ${_mptable} \ mrouted \ mtest \ @@ -270,6 +270,12 @@ .if ${MK_USB} != "no" _usbdevs= usbdevs +.endif + +.if defined(NEWMOUSE) +_moused= newmoused +.else +_moused= moused .endif .if ${MACHINE_ARCH} == "arm" diff -ruN /usr/src.orig/usr.sbin/newmoused/.depend /usr/src/usr.sbin/newmoused/.depend --- /usr/src.orig/usr.sbin/newmoused/.depend Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/.depend Thu Sep 29 15:56:48 2005 @@ -0,0 +1,18 @@ +# filters.c moused.c +filters.o: filters.c moused.h /usr/include/syslog.h \ + /usr/include/sys/cdefs.h /usr/include/sys/_types.h \ + /usr/include/machine/_types.h /usr/include/sys/mouse.h \ + /usr/include/sys/types.h /usr/include/machine/endian.h \ + /usr/include/sys/select.h /usr/include/sys/_sigset.h \ + /usr/include/sys/_timeval.h /usr/include/sys/timespec.h \ + /usr/include/sys/ioccom.h /usr/include/sys/consio.h filter_macros.h +moused.o: moused.c /usr/include/sys/cdefs.h /usr/include/sys/select.h \ + /usr/include/sys/_types.h /usr/include/machine/_types.h \ + /usr/include/sys/_sigset.h /usr/include/sys/_timeval.h \ + /usr/include/sys/timespec.h /usr/include/sys/types.h \ + /usr/include/machine/endian.h /usr/include/sys/consio.h \ + /usr/include/sys/ioccom.h /usr/include/sys/mouse.h /usr/include/dlfcn.h \ + /usr/include/err.h /usr/include/errno.h /usr/include/fcntl.h \ + /usr/include/stdarg.h /usr/include/stdio.h /usr/include/sys/_null.h \ + /usr/include/stdlib.h /usr/include/unistd.h /usr/include/sys/unistd.h \ + moused.h /usr/include/syslog.h diff -ruN /usr/src.orig/usr.sbin/newmoused/FILTERS /usr/src/usr.sbin/newmoused/FILTERS --- /usr/src.orig/usr.sbin/newmoused/FILTERS Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/FILTERS Thu Sep 15 15:06:25 2005 @@ -0,0 +1,32 @@ +Filters are somewhat limited in usefulness. Examples of filters are: + +* emulate 3 button +* virtual scrolling +* z-axis mappings + +To make writing filters easier, I was considering writing a bunch of C +macros to create a sort of virtual language that enables filter writing +to be easier. + +Things like + +GET_BUTTON_STATE(1) would "return" the state of button 1 (1 for held, 0 for not) +GET_X_DELTA would return the X delta (u.data.x) +GET_Y_DELTA, etc + +MOUSE_STATE(foo) could be used to "declare" a mouse state object +SAVE_MOUSE_STATE(foo) could be used to save the current mouse state +Is this necessary? Can there just be a 'SAVE_MOUSE_STATE' doohickey that will +save the state somewhere? Will multiple independent saves be necessary? + +What else? + +There needs to be a way to declare "I need to wait on a timeout" for +things like virtual scrolling and emulate-3-button and such. +So, perhaps a + +NEED_TIMEOUT(200) would say "in the next round of select(2), wait for +200ms." This is a single instance timeout, the next round of select will +have an unlimited timeout. + + diff -ruN /usr/src.orig/usr.sbin/newmoused/MODULES /usr/src/usr.sbin/newmoused/MODULES --- /usr/src.orig/usr.sbin/newmoused/MODULES Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/MODULES Thu Sep 15 15:06:25 2005 @@ -0,0 +1,29 @@ +Modules are the meat of what moused will do. Each individual module will +support a specific kind of mouse (ideally). + +moused deals with minor things like setting up default values on the +rodent_t structure. Plugins will handle the meat (talking to devices) + +How it works: + - Startup moused with whatever arguments (-m specifies module name) + * Example: moused -m command + - moused parses options and loads the 'command' module + (moused_command.so) with dlopen(3) + - If this fails for some reason, moused exits with error. + - The module's init function is called and passed a rodent_t*, argc, + and argv. 'argc' and 'argv' do NOT include options handled by moused + itself. This is so you can do your own option processing in your + module. + * Example: ./moused -m command -- -t Testing + Everything past the '--' gets sent to the init function as argc and argv. + - The module's probe function is then called. If it returns + MODULE_PROBE_SUCCESS, then the run function is called. + - The probe and run functions are passed a rodent_t* as the only + argument. + + - Modules will operate however they need to. When mouse activity needs + to be passed to the system, modules will need to pass a mouse_info_t* + to rodent.update(). This in-turn calls the proper ioctl() on + /dev/consolectl to indicate the given activity. + + * An example module is the 'command' module (modules/command). diff -ruN /usr/src.orig/usr.sbin/newmoused/Makefile /usr/src/usr.sbin/newmoused/Makefile --- /usr/src.orig/usr.sbin/newmoused/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/Makefile Thu Apr 13 15:29:25 2006 @@ -0,0 +1,17 @@ +# $FreeBSD: src/usr.sbin/moused/Makefile,v 1.6 2001/03/26 14:40:51 ru Exp $ +# +PROG= moused +SRCS= moused.c filters.c +INCS= moused.h filter_macros.h + +SUBDIR= modules + +# XXX: Temporary hack. Install target fails without this. +# BINDIR=/usr/sbin + +#MAN= moused.8 +NO_MAN= # Yet. + +#CFLAGS+=-g + +.include diff -ruN /usr/src.orig/usr.sbin/newmoused/build.sh /usr/src/usr.sbin/newmoused/build.sh --- /usr/src.orig/usr.sbin/newmoused/build.sh Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/build.sh Sat Dec 24 04:39:16 2005 @@ -0,0 +1,15 @@ +#!/bin/sh + +MODULES="sysmouse synaptics generic" +domake() { + $MAKE $* + for i in $MODULES; do + $MAKE -C modules/$i $* + done + + $MAKE -C lib/ps2 $* +} + +MAKE="make" +domake $* + diff -ruN /usr/src.orig/usr.sbin/newmoused/config.c /usr/src/usr.sbin/newmoused/config.c --- /usr/src.orig/usr.sbin/newmoused/config.c Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/config.c Tue Mar 28 02:20:54 2006 @@ -0,0 +1,47 @@ +/* Config file parser + * + * Similar syntax to termcap/remote/others? + */ + +/* File: /etc/moused.conf + * Same format as termcap databases + */ + +#define _PATH_MOUSED_CONF "/etc/moused.conf" + +static char *db_array[3] = { _PATH_MOUSED_CONF, 0, 0 }; + +char *getmouse(char *mouse) { + int stat; + char *bp; + if ((stat = cgetent(&bp, db_array, mouse)) < 0) { + perror("Failed to find mouse"); + return 0; + } + return bp; +} + + + +int main(int argc, char **argv) { + char *bp; + char *val; + bp = getmouse("synaptics"); + + if (bp == 0) { + printf("getmouse failed\n"); + exit(1); + } + + if (cgetstr(bp, "virtscroll", &val) < 0) { + printf("cgetstr failed\n"); + return 0; + } + + if (cgetcap(bp, "notouchpad", ':') > 0) { + printf("Notouchpad specified\n"); + } + printf("val: %s\n", val); + + return 0; +} diff -ruN /usr/src.orig/usr.sbin/newmoused/filter_macros.h /usr/src/usr.sbin/newmoused/filter_macros.h --- /usr/src.orig/usr.sbin/newmoused/filter_macros.h Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/filter_macros.h Thu Sep 15 16:58:33 2005 @@ -0,0 +1,52 @@ +/* + * Happy macros for moused filters + * Makes programming easier? + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + + +/* + * XXX: Technically, we don't need *any* of these includes, do we? + * We're just defining macros, afterall. But do we want to require filters.c + * to have sys/mouse.h and sys/consio.h? Filters using these macros shouldn't + * need to care about what the underlying structures are. + */ +#include +#include + +/** + * Basic Stuff + */ + +#define FILTER(name) static void filter_ ## name(mouse_info_t *delta, int noop) +#define RESTORE_STATE() (memcpy(delta, &(rodent.state), sizeof(mouse_info_t))) +#define RAW_UPDATE() (ioctl(rodent.cfd, CONS_MOUSECTL, delta)) + +/** + * Mouse state accessor/mutator macros + */ + +#define MOUSEDATA (delta->u.data) +#define GET_BUTTON_STATE(x) (MOUSEDATA.buttons & (1 << (x - 1))) +#define GET_MOUSE_X() (MOUSEDATA.x) +#define GET_MOUSE_Y() (MOUSEDATA.y) +#define GET_MOUSE_Z() (MOUSEDATA.z) + +#define SET_BUTTON_STATE(button) (MOUSEDATA.buttons |= (1 << (button - 1))) +#define CLEAR_BUTTON_STATE(button) (MOUSEDATA.buttons &= ~(1 << (button - 1))) +#define SET_MOUSE_DELTA(axis, delta) MOUSEDATA.axis = delta +#define SET_MOUSE_X(delta) (SET_MOUSE_DELTA(x, delta)) +#define SET_MOUSE_Y(delta) (SET_MOUSE_DELTA(y, delta)) +#define SET_MOUSE_Z(delta) (SET_MOUSE_DELTA(z, delta)) + +/** + * Helpful macros to let filters do magical things + */ + +/* Tell moused to wait for 'ms' milliseconds next time around */ +#define NEED_TIMEOUT(ms) rodent.sleeptime.tv_usec = ms * 1000 + diff -ruN /usr/src.orig/usr.sbin/newmoused/filters.c /usr/src/usr.sbin/newmoused/filters.c --- /usr/src.orig/usr.sbin/newmoused/filters.c Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/filters.c Tue Mar 21 22:35:17 2006 @@ -0,0 +1,173 @@ +/* + * Filters go here + */ + +#include +#include +#include "moused.h" +#include "filter_macros.h" + +/* rodent comes from moused.c */ +extern rodent_t rodent; + +/** + * Virtual Scrolling + */ +static int scroll_state; +static struct { + int x; + int y; +} scroll_distance; + +#define SCROLL_DISTANCE_THRESHOLD 3 + +#define SCROLL_READY 0 +#define SCROLL_PREPARED 1 +#define SCROLL_ING 2 +#define SCROLL_TIMEOUT 3 + +/* Virtual Scrolling filter */ +static void filter_virtual_scroll(mouse_info_t *delta, int noop) { + if (noop == 1) { /* timeout */ + warnx("timeout!"); + if (scroll_state == SCROLL_PREPARED) { + RESTORE_STATE(); + scroll_state = SCROLL_TIMEOUT; + } + } else { + if (GET_BUTTON_STATE(2) > 0) { + if (scroll_state == SCROLL_TIMEOUT) + return; + + if (scroll_state == SCROLL_READY) + scroll_state = SCROLL_PREPARED; + + if (GET_MOUSE_X() != 0 || GET_MOUSE_Y() != 0) { + if (scroll_state == SCROLL_PREPARED) + scroll_state = SCROLL_ING; + + scroll_distance.x += GET_MOUSE_X(); + scroll_distance.y += GET_MOUSE_Y(); + + if (scroll_distance.y > rodent.virtual_scroll_threshold) { + SET_MOUSE_Z(1); + scroll_distance.y = scroll_distance.x = 0; + } else if (scroll_distance.y < 0 - rodent.virtual_scroll_threshold) { + SET_MOUSE_Z(-1); + scroll_distance.y = scroll_distance.x = 0; + } + /* XXX: I don't think we can scroll up/down and left/right at the + * same time. Hence, we 'else if' here instead of 'if' */ + else if (scroll_distance.x > rodent.virtual_scroll_threshold) { + SET_MOUSE_Z(2); + scroll_distance.y = scroll_distance.x = 0; + } else if (scroll_distance.x < 0 - rodent.virtual_scroll_threshold) { + SET_MOUSE_Z(-2); + scroll_distance.y = scroll_distance.x = 0; + } + + /* Don't move! */ + SET_MOUSE_X(0); + SET_MOUSE_Y(0); + } + + /* Don't click middle */ + CLEAR_BUTTON_STATE(2); + + if (SCROLL_PREPARED == scroll_state) + NEED_TIMEOUT(100); + } else { + if (SCROLL_PREPARED == scroll_state) { + SET_BUTTON_STATE(2); + RAW_UPDATE(); + CLEAR_BUTTON_STATE(2); + } + scroll_state = SCROLL_READY; + } + } +} + +/* Constant Acceleration filter */ +static void filter_linear_acceleration(mouse_info_t *delta, int noop) { + SET_MOUSE_X(GET_MOUSE_X() * rodent.accelx); + SET_MOUSE_Y(GET_MOUSE_Y() * rodent.accely); +} + +/* Exponential Acceleration filter + * + * Some people may like this better than constant acceleration. It allows for + * more control at slower speeds + */ +static void filter_exponential_acceleration(mouse_info_t *delta, int noop) { + /* Multiply mouse movement based on instantaneous speed? */ + + int x = GET_MOUSE_X(); + int y = GET_MOUSE_Y(); + + /* XXX: Change these constants to be something configurable? */ + if (abs(x) > 3) + x += (x * 1000 / 900); + if (abs(y) > 3) + y += (y * 1000 / 900); + + if (rodent.verbose > 4) + warnx("old/new: (%d, %d) -> (%d, %d)", GET_MOUSE_X(), GET_MOUSE_Y(), x, y); + + SET_MOUSE_X(x); + SET_MOUSE_Y(y); +} + +/** + * Emulate 3 Button filter + */ + +static int emulate3_state; +#define EMULATE_WAITING 1 +#define EMULATE_ING 2 + +static void filter_emulate_3_button(mouse_info_t *delta, int noop) { + if (noop == 1) { + emulate3_state = 0; + RESTORE_STATE(); + } else { + /* Check if we're holding left and right buttons */ + if (GET_BUTTON_STATE(1) > 0 && GET_BUTTON_STATE(3) > 0) { + if (EMULATE_WAITING == emulate3_state) + emulate3_state = EMULATE_ING; + if (EMULATE_ING == emulate3_state) + SET_BUTTON_STATE(2); + } else if (GET_BUTTON_STATE(1) > 0 || GET_BUTTON_STATE(3)) { + emulate3_state = EMULATE_WAITING; + NEED_TIMEOUT(50); + } else { + if (EMULATE_ING == emulate3_state) { + } + emulate3_state = 0; + } + CLEAR_BUTTON_STATE(1); + CLEAR_BUTTON_STATE(3); + } +} + +/** + * Chord Middle + */ + +FILTER(chord_middle) { + /* XXX: Chord middle.... what's this do? */ +} + +void filter(mouse_info_t *delta, int noop) { + if (rodent.flags & FLAG_ACCELERATION) + //filter_linear_acceleration(delta, noop); + filter_exponential_acceleration(delta, noop); + + if (rodent.flags & FLAG_EMULATE_3_BUTTON) + filter_emulate_3_button(delta, noop); + + if (rodent.flags & FLAG_CHORD_MIDDLE) + filter_chord_middle(delta, noop); + + if (rodent.flags & FLAG_VIRTUAL_SCROLL) + filter_virtual_scroll(delta, noop); +} Binary files /usr/src.orig/usr.sbin/newmoused/filters.o and /usr/src/usr.sbin/newmoused/filters.o differ diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/Makefile /usr/src/usr.sbin/newmoused/modules/Makefile --- /usr/src.orig/usr.sbin/newmoused/modules/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/Makefile Thu Apr 13 15:27:56 2006 @@ -0,0 +1,7 @@ + +SUBDIR= command generic synaptics sysmouse + +# These modules aren't ready: +# debugsysmouse mouseman serial_common uhid-synaptics + +.include diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/command/Makefile /usr/src/usr.sbin/newmoused/modules/command/Makefile --- /usr/src.orig/usr.sbin/newmoused/modules/command/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/command/Makefile Thu Apr 13 20:42:44 2006 @@ -0,0 +1,8 @@ +LIB=moused_command +SRCS=moused_command.c ../../moused.h + +# This is needed to convince bsd.lib.mk to build a shared library +SHLIB_MAJOR=1 +SHLIB_NAME=moused_command.so.$(SHLIB_MAJOR) + +.include diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/command/README /usr/src/usr.sbin/newmoused/modules/command/README --- /usr/src.orig/usr.sbin/newmoused/modules/command/README Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/command/README Thu Sep 15 15:06:25 2005 @@ -0,0 +1,20 @@ +The command module reads line-based commands from stdin and tells the mouse to dance for you. + +Commands: + +movex + - Moves the mouse along the X axis left or right (depending on positive/negative values) +movey + - Moves the mouse along the Y axis up or down (depending on positive/negative values) +click [button2 ... buttonN] + - "clicks" using all of the specified buttons + + +Examples: +movex -4 + - Move the mouse 4 pixels to the left. +movey 15 + - Move the mouse 15 pixels down +click 2 + - Click mouse button 2 + Binary files /usr/src.orig/usr.sbin/newmoused/modules/command/libmoused_command.a and /usr/src/usr.sbin/newmoused/modules/command/libmoused_command.a differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/command/libmoused_command_p.a and /usr/src/usr.sbin/newmoused/modules/command/libmoused_command_p.a differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/command/moused_command.So and /usr/src/usr.sbin/newmoused/modules/command/moused_command.So differ diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/command/moused_command.c /usr/src/usr.sbin/newmoused/modules/command/moused_command.c --- /usr/src.orig/usr.sbin/newmoused/modules/command/moused_command.c Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/command/moused_command.c Thu Sep 15 15:06:25 2005 @@ -0,0 +1,121 @@ +/* + * Demonstrative newmoused module + * + * Reads text-based commands from standard input tellint + * the mouse how to move, etc. + */ + +#include + +#include +#include + +#include "../../moused.h" +#include +#include +#include +#include +#include + +static const int BUFLEN = 512; + +static void command(rodent_t *rodent, char *buf); + +/* + * Normally we'd be poking rodent.device and such to figure out + * if it's the kind of mouse we support. However, since this + * module doesn't actually access mouse hardware, we will + * always return SUCCESS. + * + * XXX: Should we return FAIL if there is a device specified? + * Or should we check if the device specified is a file or file descriptor? + * + */ +MOUSED_PROBE_FUNC { + return MODULE_PROBE_SUCCESS; +} + +MOUSED_INIT_FUNC { + int c; + + while (-1 != (c = getopt(argc, argv, "t:"))) { + switch (c) { + case 't': + printf("'t' option: %s\n", optarg); break; + default: + printf("Foo: %c\n", optopt); + } + } + +} + +MOUSED_RUN_FUNC { + char buf[BUFLEN]; + int len = 0; + memset(buf, 0, BUFLEN); + + while (!feof(stdin)) { + int bytes; + char *eol; + + /* Read data from stdin */ + if (len < BUFLEN) { + bytes = fread(buf + len, 1, 1, stdin); + len += bytes; + } else { + /* we've hit buffer length, line is definately too long, reset */ + warnx("Input buffer full, clearing... (Line too long?)"); + len = 0; + } + + /* Process data */ + while (NULL != (eol = strchr(buf, '\n'))) { + /* Null the EOL so we can do string functions on it */ + *eol = '\0'; + command(rodent, buf); + + /* Shift the buffer over */ + strlcpy(buf, (eol + 1), BUFLEN); + len -= (eol - buf) + 1; + } + } +} + +static void command(rodent_t *rodent, char *buf) { + char *string = buf; + char *tok; + int len = strlen(string); + mouse_info_t delta; + + memset(&delta, 0, sizeof(mouse_info_t)); + + tok = strsep(&string, " "); + + /* XXX: MOUSE_MOTION_EVENT and MOUSE_ACTION produce the same results?! */ + //delta.operation = MOUSE_MOTION_EVENT; /* Seems to only let movement happen */ + delta.operation = MOUSE_ACTION; /* appears to let mouse button actions work */ + + if (strcmp("movex", tok) == 0) { + tok = strsep(&string, " "); + delta.u.data.x = atoi(tok); + } else if (strcmp("movey", tok) == 0) { + tok = strsep(&string, " "); + delta.u.data.y = atoi(tok); + } else if (strcmp("click", tok) == 0) { + while (NULL != (tok = strsep(&string, " "))) { + int button = atoi(tok); + if (button > 0 && button < 32) + delta.u.data.buttons |= (1 << button - 1); + else + warnx("Invalid button: %d", button); + } + printf("Buttons: %08x\n", delta.u.data.buttons); + rodent->update(&delta); + delta.u.data.buttons = 0; + printf("Buttons: %08x\n", delta.u.data.buttons); + } else { + printf("Unknown command: %s\n", tok); + } + + rodent->update(&delta); +} Binary files /usr/src.orig/usr.sbin/newmoused/modules/command/moused_command.o and /usr/src/usr.sbin/newmoused/modules/command/moused_command.o differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/command/moused_command.po and /usr/src/usr.sbin/newmoused/modules/command/moused_command.po differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/command/moused_command.so and /usr/src/usr.sbin/newmoused/modules/command/moused_command.so differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/command/moused_command.so.1 and /usr/src/usr.sbin/newmoused/modules/command/moused_command.so.1 differ diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/debugsysmouse/Makefile /usr/src/usr.sbin/newmoused/modules/debugsysmouse/Makefile --- /usr/src.orig/usr.sbin/newmoused/modules/debugsysmouse/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/debugsysmouse/Makefile Thu Apr 13 20:42:51 2006 @@ -0,0 +1,8 @@ +LIB=moused_debugsysmouse +SRCS=debugsysmouse.c ../../moused.h + +# This is needed to convince bsd.lib.mk to build a shared library +SHLIB_MAJOR=1 +SHLIB_NAME=moused_debugsysmouse.so.$(SHLIB_MAJOR) + +.include diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/debugsysmouse/debugsysmouse.c /usr/src/usr.sbin/newmoused/modules/debugsysmouse/debugsysmouse.c --- /usr/src.orig/usr.sbin/newmoused/modules/debugsysmouse/debugsysmouse.c Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/debugsysmouse/debugsysmouse.c Sat Dec 24 03:36:35 2005 @@ -0,0 +1,169 @@ +/* + * new moused module for ums(4) mice + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../moused.h" + +static void (*logmsg)(int, int, const char *, ...) = NULL; + +static void activity(rodent_t *rodent, char *packet); +static void printbits(char packet); +static int tryproto(rodent_t *rodent, int proto); +static char *getmouseproto(int proto); + +static int mouseproto = MOUSE_PROTO_SYSMOUSE; + +static struct mouse_protomap { + int proto; + char *name; +} protomap[] = { + { .proto = MOUSE_PROTO_SYSMOUSE, .name = "sysmouse" }, + { .proto = MOUSE_PROTO_MSC, .name = "mousesystems" }, +}; + +MOUSED_INIT_FUNC { + int c; + char *type = "sysmouse"; + logmsg = rodent->logmsg; + + while (-1 != (c = getopt(argc, argv, "t:"))) { + switch (c) { + case 't': + type = optarg; break; + } + } + + if (strcmp(type, "sysmouse") == 0) { + mouseproto = MOUSE_PROTO_SYSMOUSE; + } else if ((strcmp(type, "mousesystems") == 0) + || (strcmp(type, "msc") == 0)) { + mouseproto = MOUSE_PROTO_MSC; + } else { + warnx("Unknown protocol '%s' - defaulting to sysmouse", type); + } +} + +MOUSED_PROBE_FUNC { + int level = 0; + rodent->mfd = open(rodent->device, O_RDWR); + + if (-1 == rodent->mfd) + logfatal(1, "Unable to open %s", rodent->device); + + if (tryproto(rodent, mouseproto) == 0) { + /* Try the other protocol */ + mouseproto = (mouseproto == MOUSE_PROTO_SYSMOUSE ? + MOUSE_PROTO_MSC : MOUSE_PROTO_SYSMOUSE); + if (tryproto(rodent, mouseproto) == 0) + return MODULE_PROBE_FAIL; + } + + close(rodent->mfd); + + return MODULE_PROBE_SUCCESS; +} + +MOUSED_HANDLER_INIT_FUNC { + warnx("init"); + + rodent->mfd = open(rodent->device, O_RDWR); + + if (-1 == rodent->mfd) + logfatal(1, "Unable to open %s", rodent->device); + + if (NULL == rodent->packet) + rodent->packet = malloc(rodent->mode.packetsize); +} + +MOUSED_HANDLER_FUNC { + int bytes; + + bytes = read(rodent->mfd, rodent->packet, rodent->mode.packetsize); + if (bytes < 0) + return; + //logfatal(1, "Error reading from mousey"); + + if (bytes == rodent->mode.packetsize) + activity(rodent, rodent->packet); + else + logfatal(1, "Unexpected data. Needed packet of size %d, got %d", + rodent->mode.packetsize, bytes); +} + +static void activity(rodent_t *rodent, char *packet) { + mouse_info_t delta; + int x; + + delta.operation = MOUSE_ACTION; + delta.u.data.buttons = 0; + delta.u.data.x = delta.u.data.y = delta.u.data.z = 0; + + if (0) + { + for (x = 0; x < 8; x++) + printf("%02x ", (*(packet + x) & 0xff)); + printf("\n"); + printbits(*packet); + } + + /* sysmouse(4) details what is in the 8-byte packets */ + + delta.u.data.buttons |= NBIT(*packet, 3) + | NBIT(*packet, 2) << 1 + | NBIT(*packet, 1) << 2; + + /* Bytes 2 and 4 are horizontal */ + delta.u.data.x = (*(packet + 1) + *(packet + 3)); + + /* Bytes 3 and 5 are vertical */ + delta.u.data.y = 0 - (*(packet + 2) + *(packet + 4)); + + /* sysmouse adds z-axis changes */ + if (MOUSE_PROTO_SYSMOUSE == mouseproto) + delta.u.data.z = (*(packet + 5) + *(packet + 6)); + + printf("(%d,%d) Z:%d B:", delta.u.data.x, delta.u.data.y, delta.u.data.z); + printbits(delta.u.data.buttons & 0xff); +} + +static void printbits(char byte) { + int x; + for (x = 1; x <= 8; x++) { + printf("%d", BIT(byte, x)); + } + printf("\n"); +} + +static int tryproto(rodent_t *rodent, int proto) { + int level; + warnx("Trying %s protocol", getmouseproto(proto)); + + for (level = 0; level < 3; level++) { + /* Set the driver operation level */ + ioctl(rodent->mfd, MOUSE_SETLEVEL, &level); + ioctl(rodent->mfd, MOUSE_GETMODE, &(rodent->mode)); + if (mouseproto == rodent->mode.protocol) + return 1; + } + + return 0; +} + +static char *getmouseproto(int proto) { + int x; + for (x = 0; x < (sizeof(protomap) / sizeof(struct mouse_protomap)); x++) { + if (protomap[x].proto == proto) + return protomap[x].name; + } +} diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/generic/Makefile /usr/src/usr.sbin/newmoused/modules/generic/Makefile --- /usr/src.orig/usr.sbin/newmoused/modules/generic/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/generic/Makefile Thu Apr 13 20:44:33 2006 @@ -0,0 +1,13 @@ +LIB= moused_generic +SRCS= generic.c ../../moused.h +LDADD= -lps2 + +# This is needed to convince bsd.lib.mk to build a shared library +SHLIB_MAJOR=1 +SHLIB_NAME=moused_generic.so.$(SHLIB_MAJOR) + + +#CFLAGS+=-I../../lib/ps2 +#LDFLAGS+=-lps2 + +.include Binary files /usr/src.orig/usr.sbin/newmoused/modules/generic/generic.So and /usr/src/usr.sbin/newmoused/modules/generic/generic.So differ diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/generic/generic.c /usr/src/usr.sbin/newmoused/modules/generic/generic.c --- /usr/src.orig/usr.sbin/newmoused/modules/generic/generic.c Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/generic/generic.c Thu Apr 13 20:27:42 2006 @@ -0,0 +1,120 @@ +/* + * Generic PS/2 Mouse + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define MOUSE_BUTTON(x) (1 << (x - 1)) + +#define tv2int(x) ((x.tv_sec * 1000000) + x.tv_usec) + +static void printbits(char val) { + int i; + for (i = 7; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void printbits_int(int val) { + int i; + for (i = sizeof(val) * 8 - 2; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void activity(rodent_t *rodent, char *packet); +static void (*logmsg)(int, int, const char *, ...) = NULL; + +MOUSED_INIT_FUNC { + logmsg = rodent->logmsg; +} + +MOUSED_PROBE_FUNC { + char status[3]; + int val; + + ps2_openfd(rodent->mfd); + ps2_reset(); + + val = ps2_get_status(status); + + if (val != 0) + return MODULE_PROBE_FAIL; + + return MODULE_PROBE_SUCCESS; +} + +MOUSED_HANDLER_INIT_FUNC { + char status[3]; + if (rodent->verbose) + warnx("generic ps/2 init"); + + ps2_openfd(rodent->mfd); + ps2_reset(); + + rodent->mode.packetsize = 3; + if (NULL == rodent->packet) { + rodent->packet = malloc(rodent->mode.packetsize); + } + + ps2_set_packetsize(rodent->mode.packetsize); + ps2_set_syncmask(0xc0); + + ps2_enable_stream(); +} + +MOUSED_HANDLER_FUNC { + int bytes; + + /* XXX: Should this be done in libps2? + * ie; bytes = ps2_read_packet(rodent->packet) + */ + bytes = read(rodent->mfd, rodent->packet, rodent->mode.packetsize); + + if (bytes < 0) + return; + + if (bytes == rodent->mode.packetsize) + activity(rodent, rodent->packet); + else + warnx("Invalid packet size: %d", bytes); +} + +static void activity(rodent_t *rodent, char *packet) { + mouse_info_t delta; + struct timeval uptime; + + delta.operation = MOUSE_ACTION; + delta.u.data.buttons = 0; + delta.u.data.x = delta.u.data.y = delta.u.data.z = 0; + + delta.u.data.x = packet[1]; + delta.u.data.y = -packet[2]; + + if (packet[0] & 0x01) + delta.u.data.buttons |= MOUSE_BUTTON(1); + if (packet[0] & 0x02) + delta.u.data.buttons |= MOUSE_BUTTON(3); + if (packet[0] & 0x04) + delta.u.data.buttons |= MOUSE_BUTTON(2); + + //printf("1: "); printbits(packet[0]); printf("\n"); + //printf("2: "); printbits(packet[1]); printf("\n"); + //printf("3: "); printbits(packet[2]); printf("\n"); + + rodent->update(&delta); +} + Binary files /usr/src.orig/usr.sbin/newmoused/modules/generic/generic.o and /usr/src/usr.sbin/newmoused/modules/generic/generic.o differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/generic/generic.po and /usr/src/usr.sbin/newmoused/modules/generic/generic.po differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/generic/libmoused_generic.a and /usr/src/usr.sbin/newmoused/modules/generic/libmoused_generic.a differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/generic/libmoused_generic_p.a and /usr/src/usr.sbin/newmoused/modules/generic/libmoused_generic_p.a differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/generic/moused_generic.so and /usr/src/usr.sbin/newmoused/modules/generic/moused_generic.so differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/generic/moused_generic.so.1 and /usr/src/usr.sbin/newmoused/modules/generic/moused_generic.so.1 differ diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/mouseman/Makefile /usr/src/usr.sbin/newmoused/modules/mouseman/Makefile --- /usr/src.orig/usr.sbin/newmoused/modules/mouseman/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/mouseman/Makefile Thu Apr 13 20:43:05 2006 @@ -0,0 +1,13 @@ +LIB= moused_mouseman +SRCS= mouseman.c ../../moused.h +#INCS= moused.h +LDADD= -lps2 + +# This is needed to convince bsd.lib.mk to build a shared library +SHLIB_MAJOR=1 +SHLIB_NAME=moused_mouseman.so.$(SHLIB_MAJOR) + +#CFLAGS+=-I../../lib/ps2 +#LDFLAGS+=-lps2 + +.include diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/mouseman/mouseman.c /usr/src/usr.sbin/newmoused/modules/mouseman/mouseman.c --- /usr/src.orig/usr.sbin/newmoused/modules/mouseman/mouseman.c Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/mouseman/mouseman.c Tue Mar 21 22:35:17 2006 @@ -0,0 +1,159 @@ +/* + * Mouseman Protocol (Logitech PS2PLUS) + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "../../moused.h" +#include "../../lib/ps2/ps2.h" + +#define MOUSE_BUTTON(x) (1 << (x - 1)) + +#define tv2int(x) ((x.tv_sec * 1000000) + x.tv_usec) + +/* Logitech PS2++ protocol */ +#define MOUSE_PS2PLUS_CHECKBITS(b) ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f)) +#define MOUSE_PS2PLUS_PACKET_TYPE(b) (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4)) + +static void printbits(char val) { + int i; + for (i = 7; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void printbits_int(int val) { + int i; + for (i = sizeof(val) * 8 - 2; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void activity(rodent_t *rodent, char *packet); +static void (*logmsg)(int, int, const char *, ...) = NULL; + +MOUSED_INIT_FUNC { + logmsg = rodent->logmsg; +} + +/* + * Try and enable fancy mouseman protocol + * + * This code paraphased from old psm.c's enable_mmanplus function + */ +MOUSED_PROBE_FUNC { + char status[3]; + int val; + + ps2_openfd(rodent->mfd); + ps2_reset(); + ps2_disable_stream(); + + val = ps2_set_scaling(1); + if (val) { + logmsg(0, errno, "Set scaling failed: %d", val); + return MODULE_PROBE_FAIL; + } + if (ps2_ext_command(0x39) || ps2_ext_command(0xdb)) { + logmsg(0, errno, "Ext commands failed"); + return MODULE_PROBE_FAIL; + } + + val = ps2_get_status(status); + printf("status: %d\n", val); + + if (val != 0) + return MODULE_PROBE_FAIL; + + if (status[0] & MOUSE_PS2PLUS_SYNCMASK != MOUSE_PS2PLUS_SYNC) { + logmsg(1, errno, "Syncmask check failed"); + return MODULE_PROBE_FAIL; + } + if (status[1] & 0xc3 != 0xc2) { + logmsg(1, errno, "byte2 check failed"); + return MODULE_PROBE_FAIL; + } + if (!MOUSE_PS2PLUS_CHECKBITS(status)) { + logmsg(1, errno, "ps2plus checkbits failed"); + return MODULE_PROBE_FAIL; + } + if (!MOUSE_PS2PLUS_PACKET_TYPE(status) != 0) { + logmsg(1, errno, "ps2plus packet type check failed"); + return MODULE_PROBE_FAIL; + } + + ps2_enable_stream(); + + return MODULE_PROBE_SUCCESS; +} + +MOUSED_HANDLER_INIT_FUNC { + char status[3]; + if (rodent->verbose) + warnx("mouseman ps2plus init"); + + ps2_openfd(rodent->mfd); + ps2_reset(); + + rodent->mode.packetsize = 3; + if (NULL == rodent->packet) { + rodent->packet = malloc(rodent->mode.packetsize); + } + + ps2_set_packetsize(rodent->mode.packetsize); + ps2_set_syncmask(0xc0); + + ps2_enable_stream(); +} + +MOUSED_HANDLER_FUNC { + int bytes; + + /* XXX: Should this be done in libps2? + * ie; bytes = ps2_read_packet(rodent->packet) + */ + bytes = read(rodent->mfd, rodent->packet, rodent->mode.packetsize); + + if (bytes < 0) + return; + + if (bytes == rodent->mode.packetsize) + activity(rodent, rodent->packet); + else + warnx("Invalid packet size: %d", bytes); +} + +static void activity(rodent_t *rodent, char *packet) { + mouse_info_t delta; + struct timeval uptime; + + delta.operation = MOUSE_ACTION; + delta.u.data.buttons = 0; + delta.u.data.x = delta.u.data.y = delta.u.data.z = 0; + + delta.u.data.x = packet[1]; + delta.u.data.y = -packet[2]; + + if (packet[0] & 0x01) + delta.u.data.buttons |= MOUSE_BUTTON(1); + if (packet[0] & 0x02) + delta.u.data.buttons |= MOUSE_BUTTON(3); + if (packet[0] & 0x04) + delta.u.data.buttons |= MOUSE_BUTTON(2); + + //printf("1: "); printbits(packet[0]); printf("\n"); + //printf("2: "); printbits(packet[1]); printf("\n"); + //printf("3: "); printbits(packet[2]); printf("\n"); + + rodent->update(&delta); +} + diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/serial_common/SERIALMICE /usr/src/usr.sbin/newmoused/modules/serial_common/SERIALMICE --- /usr/src.orig/usr.sbin/newmoused/modules/serial_common/SERIALMICE Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/serial_common/SERIALMICE Thu Sep 15 15:06:25 2005 @@ -0,0 +1,16 @@ +Serial mice are going to probably want a common API. + +This api will be defined here in serial_common. I'm not sure how this +should work. Serial modules should require this to be built as a shared +library and link to it dynamically? + +Said API should include macros for doing termios(4) stuffs (such as DTR and +other stuffs). I'm not that well informed about serial mice stuffs yet, +but I'll work on that later as requests come in for serial mice support. + +api: + - set/get baud rate + - DTR and RTS bits (get/set) + - write bytes/bits + - read bytes? + diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/synaptics/179.2.txt /usr/src/usr.sbin/newmoused/modules/synaptics/179.2.txt --- /usr/src.orig/usr.sbin/newmoused/modules/synaptics/179.2.txt Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/synaptics/179.2.txt Mon Feb 20 23:13:31 2006 @@ -0,0 +1,552 @@ +/* + * Synaptics touchpad + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "../../moused.h" +#include "../../lib/ps2/ps2.h" + +#define SGN(x) ((x)>=0?1:-1) + +#define MOUSE_BUTTON(x) (1 << (x - 1)) +#define SYNAPTICS_X (((packet[3] & 0x10) << 8) | \ + ((packet[1] & 0x0F) << 8) | \ + packet[4] & 0xFF) + +#define SYNAPTICS_Y (((packet[3] & 0x20) << 7) | \ + ((packet[1] & 0xF0) << 4) | \ + packet[5] & 0xFF) + +#define tv2int(x) (((x).tv_sec * 1000000) + (x).tv_usec) +#define TAP_TIMEOUT 125000 +#define LOW_SPEED_THRESHOLD 20 +#define SQUELCH_LEVEL 3 +#define MIN_MOVEMENT 2 + +/* "pressure" 20-30 still shows up even if I'm not touching the pad */ +#define TOUCH_THRESHOLD 35 + +/* "tap" pressure minimum */ +#define TAP_THRESHOLD 40 + +/* edges for scrolling and clickdrag helper */ +#define EDGE_BOTTOM 1500 +#define EDGE_TOP 4500 +#define EDGE_LEFT 1500 +#define EDGE_RIGHT 5500 + +typedef struct synaptics { + int w; /* palm/finger detection */ + int x; /* absolute x coordinate */ + int y; /* absolute y coordinate */ + int z; /* z pressure (capacitance measure) */ + int buttons; /* bitmap of buttons */ + + int guestbuttons; + int touchbuttons; + int clickdrag; + int scrollv; + int scrollh; + + /* Last packet's coordinates */ + int finger; + int oldx; + int oldy; + struct timeval lastfingertime; + int tap; + int tapw; /* palm/finger state during last tap */ + int zmax; + int drag; + + /* Rolling averages */ + int xaverage; + int yaverage; + int squelch; +} synaptics_t; + +/* From libkern.h */ +static __inline int imax(int a, int b) { return (a > b ? a : b); } + +static void printbits(char val) { + int i; + for (i = 7; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void printbits_int(int val) { + int i; + for (i = sizeof(val) * 8 - 2; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void activity(rodent_t *rodent, char *packet); +static void (*logmsg)(int, int, const char *, ...) = NULL; +static void smoothdata(mouse_info_t *delta); +void guestdata(char *packet, rodent_t *rodent); +void touchpaddata(char *packet, rodent_t *rodent); +static int timecmplt(struct timeval *tv, int timeout); + +static synaptics_t synaptics; + +MOUSED_INIT_FUNC { + logmsg = rodent->logmsg; +} + +MOUSED_PROBE_FUNC { + char status[3]; + + /* XXX: Shouldn't moused.c do the open? */ + rodent->mfd = open(rodent->device, O_RDWR); + if (rodent->mfd == -1) + logfatal(1, "Unable to open %s", rodent->device); + + ps2_openfd(rodent->mfd); + ps2_reset(); + + ps2_disable_stream(); + + /* Synaptics Probe, as per documentation */ + ps2_ext_command(0); + ps2_get_status(status); + + if (status[1] != 0x47) { + warnx("This is not a Synaptics device"); + return MODULE_PROBE_FAIL; + } + + /* Re-enable streaming */ + ps2_enable_stream(); + + if (rodent->verbose) + warnx("Synaptics Touchpad version %d.%d", status[2] & 0x0F, status[0]); + + close(rodent->mfd); + + return MODULE_PROBE_SUCCESS; +} + +MOUSED_HANDLER_INIT_FUNC { + char status[3]; + if (rodent->verbose > 1) + warnx("synaptics init"); + + rodent->mfd = open(rodent->device, O_RDWR); + if (rodent->mfd == -1) + logfatal(1, "Unable to open %s", rodent->device); + + ps2_openfd(rodent->mfd); + ps2_reset(); + + rodent->mode.packetsize = 6; + if (NULL == rodent->packet) { + rodent->packet = malloc(rodent->mode.packetsize); + } + + ps2_set_packetsize(rodent->mode.packetsize); + + /* + * Put the touchpad in "absolute mode" + * This is done by encoding an 8-bit argument in 4 set_resolution commands + * and then sending an Set Sample Rate 20 command + */ + + /* First, disable device reporting */ + ps2_disable_stream(); + + /* Enable Absolute mode, high packet rate, and Wmode ( 0xC1 ) */ + ps2_ext_command(0xc1); + ps2_set_sample_rate(20); /* 0x14 */ + + /* Request 'Synaptics Mode' status */ + ps2_ext_command(1); + ps2_get_status(status); + + ps2_enable_stream(); + + /* Set the syncmask of our protocol header (first byte) */ + ps2_set_syncmask(0xc8); +} + +MOUSED_HANDLER_FUNC { + int bytes; + + /* XXX: Should this be done in libps2? + * ie; bytes = ps2_read_packet(rodent->packet) + */ + bytes = read(rodent->mfd, rodent->packet, rodent->mode.packetsize); + + if (bytes < 0) + return; + + if (bytes == rodent->mode.packetsize) + activity(rodent, rodent->packet); + else + warnx("Invalid packet size: %d", bytes); +} + +static void activity(rodent_t *rodent, char *packet) { + mouse_info_t delta; + + delta.operation = MOUSE_ACTION; + delta.u.data.buttons = 0; + delta.u.data.x = delta.u.data.y = delta.u.data.z = 0; + + synaptics.buttons = synaptics.w = synaptics.x = synaptics.y = synaptics.z = 0; + + /* Finger "type" value */ + synaptics.w = ((packet[0] & 0x30) >> 2) | + ((packet[0] & 0x04) >> 1) | + ((packet[3] & 0x04) >> 2); + + /* Pressure/Contact level */ + synaptics.z = packet[2] & 0xff; + + /* Guest devices (trackpoint, for example) show up with 'w' of 3 */ + if (synaptics.w == 3) + guestdata(packet, rodent); + else + touchpaddata(packet, rodent); + + if (synaptics.drag == 1) /* Touchpad dragging */ + smoothdata(&delta); + else if (synaptics.w == 3) { /* Guest device */ + delta.u.data.x = synaptics.x; + delta.u.data.y = synaptics.y; + } + + /* We keep state on both guest and touchpad mouse buttons */ + delta.u.data.buttons = synaptics.guestbuttons | synaptics.touchbuttons; + /* XXX: y needs to be negated? */ + delta.u.data.y = -delta.u.data.y; + + synaptics.oldx = synaptics.x; + synaptics.oldy = synaptics.y; + synaptics.zmax = imax(synaptics.z, synaptics.zmax); + + /* Scrolling vertically */ + if (synaptics.scrollv) + { + int z = delta.u.data.y; + + if (rodent->verbose > 1) + printf("Scrolling vertically with: %d\n", z); + + delta.u.data.x = 0; + delta.u.data.y = 0; + delta.u.data.z = SGN(z); + + /* Send several scroll up / down messages */ + for ( ; z != 0; z -= SGN(z)) + rodent->update(&delta); + + return; + } + + /* Scrolling horizontally */ + if (synaptics.scrollh) + { + int z = delta.u.data.x; + + if (rodent->verbose > 1) + printf("Scrolling horizontally with: %d\n", z); + + delta.u.data.x = 0; + delta.u.data.y = 0; + delta.u.data.z = 2 * SGN(z); + + /* Send several scroll up / down messages */ + for ( ; z != 0; z -= SGN(z)) + rodent->update(&delta); + + return; + } + + /* Clickdrag helper */ + if (synaptics.clickdrag) + { + if (synaptics.y < EDGE_BOTTOM) + delta.u.data.y = +2; + + if (synaptics.y > EDGE_TOP) + delta.u.data.y = -2; + + if (synaptics.x < EDGE_LEFT) + delta.u.data.x = -2; + + if (synaptics.x > EDGE_RIGHT) + delta.u.data.x = +2; + } + + if (rodent->verbose > 1) + if (delta.u.data.x != 0 || delta.u.data.y != 0 || delta.u.data.buttons != 0 + || rodent->verbose > 2) + { + printf("Update: (%d,%d) %x\n", delta.u.data.x, delta.u.data.y, delta.u.data.buttons); + printf("Abs: (%d,%d)\n", synaptics.x, synaptics.y); + } + + rodent->update(&delta); +} + +static void smoothdata(mouse_info_t *delta) { + int xa, ya; /* X and Y averages */ + int x, y; + int sensitivity, xsensitivity, ysensitivity; + + if (synaptics.xaverage == 0) + synaptics.xaverage = synaptics.x; + if (synaptics.yaverage == 0) + synaptics.yaverage = synaptics.y; + + xa = synaptics.xaverage; + ya = synaptics.yaverage; + + synaptics.xaverage = (xa + synaptics.x) / 2; + synaptics.yaverage = (ya + synaptics.y) / 2; + + xsensitivity = (synaptics.xaverage - xa); + if (xsensitivity < 0) + xsensitivity = -xsensitivity; + ysensitivity = (synaptics.yaverage - ya); + if (ysensitivity < 0) + ysensitivity = -ysensitivity; + + sensitivity = (xsensitivity & ysensitivity) + 1; + + if ((synaptics.x > LOW_SPEED_THRESHOLD || synaptics.x < -LOW_SPEED_THRESHOLD) + || (synaptics.y > LOW_SPEED_THRESHOLD || synaptics.y < -LOW_SPEED_THRESHOLD)) { + synaptics.x = (synaptics.x + synaptics.oldx * 3) / 4; + synaptics.y = (synaptics.y + synaptics.oldy * 3) / 4; + + delta->u.data.x = (synaptics.x - synaptics.oldx) * 10 / 85; + delta->u.data.y = (synaptics.y - synaptics.oldy) * 10 / 85; + } else { + if (synaptics.x < -MIN_MOVEMENT) + delta->u.data.x = -1; + else if (synaptics.x > MIN_MOVEMENT) + delta->u.data.x = 1; + else + delta->u.data.x = 0; + + if (synaptics.y < -MIN_MOVEMENT) + delta->u.data.y = -1; + else if (synaptics.y > MIN_MOVEMENT) + delta->u.data.y = 1; + else + delta->u.data.y = 0; + } + + synaptics.squelch += sensitivity; + + if (synaptics.squelch < SQUELCH_LEVEL) { + delta->u.data.x = 0; + delta->u.data.y = 0; + } else + synaptics.squelch = 0; + + //printf("(movement) (%d, %d) (%02x)\n", (synaptics.x - synaptics.oldx), synaptics.y - synaptics.oldy, synaptics.buttons); +} + +void guestdata(char *packet, rodent_t *rodent) { + synaptics.x = (packet[1] & 0x10) ? packet[4] : packet[4]; + synaptics.y = (packet[1] & 0x20) ? packet[5] : packet[5]; + synaptics.z = 0; + + synaptics.guestbuttons = 0; + if (packet[1] & 0x01) + synaptics.guestbuttons |= MOUSE_BUTTON(1); + if (packet[1] & 0x02) + synaptics.guestbuttons |= MOUSE_BUTTON(3); + if (packet[1] & 0x04) + synaptics.guestbuttons |= MOUSE_BUTTON(2); + + //printf("(nipple) (%d, %d) W:%u Z:%u (%02x)\n", synaptics.x, synaptics.y, synaptics.w, synaptics.z, synaptics.buttons); +} + +void touchpaddata(char *packet, rodent_t *rodent) { + int invscrollregion; + int inhscrollregion; + + synaptics.x = SYNAPTICS_X; + synaptics.y = SYNAPTICS_Y; + + synaptics.touchbuttons = 0; + + if (packet[0] & 0x01) + synaptics.touchbuttons |= MOUSE_BUTTON(1); + if (packet[0] & 0x02) + synaptics.touchbuttons |= MOUSE_BUTTON(3); + + /* Are we in the scrolling region? */ + invscrollregion = 0; + inhscrollregion = 0; + if (synaptics.x > EDGE_RIGHT) + invscrollregion = 1; + else if (synaptics.y < EDGE_BOTTOM) + inhscrollregion = 1; + + /* Single fingers are 4 <= w <= 8 */ + if ((synaptics.w >= 4 && synaptics.w <= 8) + && (synaptics.z >= TOUCH_THRESHOLD && synaptics.z < 200)) { + +// if (rodent->verbose) +// printf("Single finger\n"); + + if (synaptics.tap > 0) { + /* we tapped last time we had a finger down, holdclick */ + if ((synaptics.finger == 0) && (timecmplt(&synaptics.lastfingertime, TAP_TIMEOUT))) + synaptics.clickdrag = MOUSE_BUTTON(1); + + if (synaptics.clickdrag) + synaptics.touchbuttons |= synaptics.clickdrag; + } + + + if (synaptics.finger == 0) { + /* Scrolling */ + if (!synaptics.scrollv && !synaptics.scrollh) + { + if (invscrollregion) { + synaptics.scrollv = 1; + if (rodent->verbose > 0) + printf("Scrolling vertically started ...\n"); + } else if (inhscrollregion) { + synaptics.scrollh = 1; + if (rodent->verbose > 0) + printf("Scrolling horizontally started ...\n"); + } + } + + synaptics.finger = 1; + gettimeofday(&synaptics.lastfingertime, NULL); + } else { + synaptics.drag = 1; + } + + //printf("(touchpad) (%d, %d) W:%u Z:%u (%02x)\n", synaptics.x, synaptics.y, synaptics.w, synaptics.z, synaptics.buttons); + } + + /* w == 0 indicates two fingers */ + else if (synaptics.w == 0 && synaptics.z > TOUCH_THRESHOLD) { + + if (rodent->verbose) + printf("Two fingers\n"); + + if (synaptics.finger == 0) { + synaptics.finger = 2; + gettimeofday(&synaptics.lastfingertime, NULL); + } else { + synaptics.drag = 1; + } + + /* XXX: Only send right mouse if this is the first set of fingers down? */ + if (synaptics.finger == 2) + synaptics.touchbuttons |= MOUSE_BUTTON(3); + + //printf("(twofinger) (%d, %d) W:%u Z:%u (%02x)\n", synaptics.x, synaptics.y, synaptics.w, synaptics.z, synaptics.buttons); + } + + /* w == 1 indicates three or more fingers */ + else if (synaptics.w == 1 && synaptics.z > TOUCH_THRESHOLD) { + + if (rodent->verbose) + printf("Three+ fingers\n"); + + /* It's difficult to have 3-finger detected first before 2finger */ + if (synaptics.finger == 0 || synaptics.finger == 2) { + synaptics.finger = 3; + gettimeofday(&synaptics.lastfingertime, NULL); + } else { + synaptics.drag = 1; + } + + /* XXX: Only send right mouse if this is the first set of fingers down? */ + if (synaptics.finger == 3) + synaptics.touchbuttons |= MOUSE_BUTTON(2); + + //printf("(threeplus) (%d, %d) W:%u Z:%u (%02x)\n", synaptics.x, synaptics.y, synaptics.w, synaptics.z, synaptics.buttons); + } + /* Unknown W: value? */ + else { + /* equate finger with button values */ + if (synaptics.z >= TOUCH_THRESHOLD) { + printf("Unknown: W:%u Z:%u (%02x)\n", synaptics.w, synaptics.z, synaptics.touchbuttons); + } + if (synaptics.finger) { + /* Finger was down previously, now it's not */ + + /* If we have to, end scrolling */ + if (synaptics.scrollh) { + synaptics.scrollh = 0; + if (rodent->verbose > 0) + printf("Scrolling horizontally ended ...\n"); + } + if (synaptics.scrollv) { + synaptics.scrollv = 0; + if (rodent->verbose > 0) + printf("Scrolling vertically ended ...\n"); + } + + /* If the finger was down less than TAP_TIMEOUT, then consider this a tap */ + if ((synaptics.zmax >= TAP_THRESHOLD) && + timecmplt(&synaptics.lastfingertime, TAP_TIMEOUT)) { + /* XXX: Some sort of special tap handling should go here. + * Handle coordinate-based taps for special clicks */ + printf("Tap!\n"); + synaptics.tap++; + synaptics.tapw = synaptics.w; /* So we know what button to click */ + } else { + if (rodent->verbose) + printf("no tap detected\n"); + synaptics.tap = 0; + } + gettimeofday(&synaptics.lastfingertime, NULL); + + + synaptics.clickdrag = 0; + synaptics.finger = 0; + synaptics.drag = 0; + synaptics.oldx = synaptics.oldy = 0; + + } + } + + /* Wait some time, then check is clickdrag is on. + * If not, consider this a click */ + if (!timecmplt(&synaptics.lastfingertime, TAP_TIMEOUT) && + synaptics.tap && + !synaptics.clickdrag) { + + printf("Clicking\n"); + if (synaptics.tapw == 0) + synaptics.touchbuttons |= MOUSE_BUTTON(3); + else if (synaptics.tapw == 1) + synaptics.touchbuttons |= MOUSE_BUTTON(2); + else if (synaptics.tapw >= 4 && synaptics.tapw <= 8) + synaptics.touchbuttons |= MOUSE_BUTTON(1); + synaptics.tap = 0; + } + + + if (rodent->verbose > 2) + printf("(%s) W:%d Z:%d (%d, %d) %02x\n", (synaptics.w == 3) ? "nipple" : "finger", synaptics.w, synaptics.z, synaptics.x, synaptics.y, synaptics.touchbuttons); +} + +static int timecmplt(struct timeval *tv, int timeout) { + struct timeval cur; + + gettimeofday(&cur, NULL); + return (tv2int(cur) - tv2int(*tv)) < timeout; +} diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/synaptics/Makefile /usr/src/usr.sbin/newmoused/modules/synaptics/Makefile --- /usr/src.orig/usr.sbin/newmoused/modules/synaptics/Makefile Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/synaptics/Makefile Thu Apr 13 20:44:23 2006 @@ -0,0 +1,12 @@ +LIB=moused_synaptics +SRCS=synaptics.c ../../moused.h +LDADD= -lps2 + +# This is needed to convince bsd.lib.mk to build a shared library +SHLIB_MAJOR=1 +SHLIB_NAME=moused_synaptics.so.$(SHLIB_MAJOR) + +#CFLAGS+=-I../../lib/ps2 -g +#LDFLAGS+=-lps2 + +.include Binary files /usr/src.orig/usr.sbin/newmoused/modules/synaptics/libmoused_synaptics.a and /usr/src/usr.sbin/newmoused/modules/synaptics/libmoused_synaptics.a differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/synaptics/libmoused_synaptics_p.a and /usr/src/usr.sbin/newmoused/modules/synaptics/libmoused_synaptics_p.a differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/synaptics/moused_synaptics.so and /usr/src/usr.sbin/newmoused/modules/synaptics/moused_synaptics.so differ Binary files /usr/src.orig/usr.sbin/newmoused/modules/synaptics/moused_synaptics.so.1 and /usr/src/usr.sbin/newmoused/modules/synaptics/moused_synaptics.so.1 differ diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/synaptics/synaptics-tapholdclick.patch /usr/src/usr.sbin/newmoused/modules/synaptics/synaptics-tapholdclick.patch --- /usr/src.orig/usr.sbin/newmoused/modules/synaptics/synaptics-tapholdclick.patch Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/synaptics/synaptics-tapholdclick.patch Sat Dec 24 06:56:24 2005 @@ -0,0 +1,19 @@ +--- synaptics.c.orig Sat Dec 24 06:55:24 2005 ++++ synaptics.c Sat Dec 24 06:55:43 2005 +@@ -326,7 +326,8 @@ + printf("Single finger\n"); + + if (synaptics.tap > 0) { +- if (timecmplt(&synaptics.lastfingertime, TAP_TIMEOUT)) ++ /* we tapped last time we had a finger down, holdclick */ ++ if ((synaptics.finger == 0) && (timecmplt(&synaptics.lastfingertime, TAP_TIMEOUT))) + synaptics.clickdrag = MOUSE_BUTTON(1); + + if (synaptics.clickdrag) +@@ -432,5 +433,5 @@ + struct timeval cur; + + gettimeofday(&cur, NULL); +- return (tv2int(cur) - tv2int(*tv) < timeout); ++ return (tv2int(cur) - tv2int(*tv)) < timeout; + } Binary files /usr/src.orig/usr.sbin/newmoused/modules/synaptics/synaptics.So and /usr/src/usr.sbin/newmoused/modules/synaptics/synaptics.So differ diff -ruN /usr/src.orig/usr.sbin/newmoused/modules/synaptics/synaptics.c /usr/src/usr.sbin/newmoused/modules/synaptics/synaptics.c --- /usr/src.orig/usr.sbin/newmoused/modules/synaptics/synaptics.c Wed Dec 31 19:00:00 1969 +++ /usr/src/usr.sbin/newmoused/modules/synaptics/synaptics.c Thu Apr 13 20:27:33 2006 @@ -0,0 +1,456 @@ +/* + * Synaptics touchpad + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define MOUSE_BUTTON(x) (1 << (x - 1)) +#define SYNAPTICS_X (((packet[3] & 0x10) << 8) | \ + ((packet[1] & 0x0F) << 8) | \ + packet[4] & 0xFF) + +#define SYNAPTICS_Y (((packet[3] & 0x20) << 7) | \ + ((packet[1] & 0xF0) << 4) | \ + packet[5] & 0xFF) + +#define tv2int(x) (((x).tv_sec * 1000000) + (x).tv_usec) +#define TAP_TIMEOUT 125000 +#define LOW_SPEED_THRESHOLD 20 +#define SQUELCH_LEVEL 3 +#define MIN_MOVEMENT 2 + +/* "pressure" 20-30 still shows up even if I'm not touching the pad */ +#define TOUCH_THRESHOLD 35 + +/* "tap" pressure minimum */ +#define TAP_THRESHOLD 40 + +typedef struct synaptics { + int w; /* palm/finger detection */ + int x; /* absolute x coordinate */ + int y; /* absolute y coordinate */ + int z; /* z pressure (capacitance measure) */ + int buttons; /* bitmap of buttons */ + + int guestbuttons; + int touchbuttons; + int clickdrag; + + /* Last packet's coordinates */ + int finger; + int oldx; + int oldy; + struct timeval lastfingertime; + int tap; + int zmax; + int drag; + + /* Rolling averages */ + int xaverage; + int yaverage; + int squelch; + + /* XXX: CHANGEABLE OPTIONS */ + int touchpad; +} synaptics_t; + +/* From libkern.h */ +static __inline int imax(int a, int b) { return (a > b ? a : b); } + +static void printbits(char val) { + int i; + for (i = 7; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void printbits_int(int val) { + int i; + for (i = sizeof(val) * 8 - 2; i >= 0; i--) { + printf("%d", (val >> i) & 1); + } +} + +static void activity(rodent_t *rodent, char *packet); +static void (*logmsg)(int, int, const char *, ...) = NULL; +static void smoothdata(mouse_info_t *delta); +void guestdata(char *packet, rodent_t *rodent); +void touchpaddata(char *packet, rodent_t *rodent); +static int timecmplt(struct timeval *tv, int timeout); + +static synaptics_t synaptics; + +/* XXX: MOVE THIS TO A CONFIG LIBRARY */ +static char *db_array[3] = { "/etc/moused.conf", 0, 0 }; + +MOUSED_INIT_FUNC { + char *bp; + long notouchpad; + + logmsg = rodent->logmsg; + + /* XXX: Move this crap to some generic moused config access function set */ + if (cgetent(&bp, db_array, "synaptics") < 0) { + logmsg(0, errno, "Unable to find config for 'synaptics' in moused.conf"); + return; + } + + /* XXX: How about: + * getconfig("notouchpad", &value, TYPE_BOOLEAN) + * getconfig("virtscroll", &value, TYPE_INT) + * getconfig("dv", &value, TYPE_STRING) + */ + if (cgetcap(bp, "notouchpad", ':') > 0) { + /* Disable touchpad */ + warnx("Disabling touchpad"); + synaptics.touchpad = 0; + } else { + synaptics.touchpad = 1; + } +} + +MOUSED_PROBE_FUNC { + char status[3]; + + ps2_openfd(rodent->mfd); + ps2_reset(); + + /* disable mouse delta reporting */ + ps2_disable_stream(); + + /* Synaptics Probe, as per documentation */ + ps2_ext_command(0); + ps2_get_status(status); + + if (status[1] != 0x47) { + warnx("This is not a Synaptics device"); + return MODULE_PROBE_FAIL; + } + + /* Re-enable streaming */ + ps2_enable_stream(); + + if (rodent->verbose) + warnx("Synaptics Touchpad version %d.%d", status[2] & 0x0F, status[0]); + + return MODULE_PROBE_SUCCESS; +} + +MOUSED_HANDLER_INIT_FUNC { + char status[3]; + if (rodent->verbose > 1) + warnx("synaptics init"); + + ps2_openfd(rodent->mfd); + ps2_reset(); + + rodent->mode.packetsize = 6; + if (NULL == rodent->packet) { + rodent->packet = malloc(rodent->mode.packetsize); + } + + ps2_set_packetsize(rodent->mode.packetsize); + + /* + * Put the touchpad in "absolute mode" + * This is done by encoding an 8-bit argument in 4 set_resolution commands + * and then sending an Set Sample Rate 20 command + */ + + /* First, disable device reporting */ + ps2_disable_stream(); + + /* Enable Absolute mode, high packet rate, and Wmode ( 0xC1 ) */ + ps2_ext_command(0xc1); + ps2_set_sample_rate(20); /* 0x14 */ + + /* Request 'Synaptics Mode' status */ + ps2_ext_command(1); + ps2_get_status(status); + + ps2_enable_stream(); + + /* Set the syncmask of our protocol header (first byte) */ + ps2_set_syncmask(0xc8); +} + +MOUSED_HANDLER_FUNC { + int bytes; + + /* XXX: Should this be done in libps2? + * ie; bytes = ps2_read_packet(rodent->packet) + */ + bytes = read(rodent->mfd, rodent->packet, rodent->mode.packetsize); + + if (bytes < 0) + return; + + if (bytes == rodent->mode.packetsize) + activity(rodent, rodent->packet); + else + warnx("Invalid packet size: %d", bytes); +} + +static void activity(rodent_t *rodent, char *packet) { + mouse_info_t delta; + + delta.operation = MOUSE_ACTION; + delta.u.data.buttons = 0; + delta.u.data.x = delta.u.data.y = delta.u.data.z = 0; + + synaptics.buttons = synaptics.w = synaptics.x = synaptics.y = synaptics.z = 0; + + /* Finger "type" value */ + synaptics.w = ((packet[0] & 0x30) >> 2) | + ((packet[0] & 0x04) >> 1) | + ((packet[3] & 0x04) >> 2); + + /* Pressure/Contact level */ + synaptics.z = packet[2] & 0xff; + + /* Guest devices (trackpoint, for example) show up with 'w' of 3 */ + if (synaptics.w == 3) + guestdata(packet, rodent); + else if (synaptics.touchpad) + touchpaddata(packet, rodent); + + if (synaptics.drag == 1) /* Touchpad dragging */ + smoothdata(&delta); + else if (synaptics.w == 3) { /* Guest device */ + delta.u.data.x = synaptics.x; + delta.u.data.y = synaptics.y; + } + + /* We keep state on both guest and touchpad mouse buttons */ + delta.u.data.buttons = synaptics.guestbuttons | synaptics.touchbuttons; + /* XXX: y needs to be negated? */ + delta.u.data.y = -delta.u.data.y; + + synaptics.oldx = synaptics.x; + synaptics.oldy = synaptics.y; + synaptics.zmax = imax(synaptics.z, synaptics.zmax); + + //if (rodent->verbose > 1) + //if (delta.u.data.x != 0 || delta.u.data.y != 0 || delta.u.data.buttons != 0 + //|| rodent->verbose > 2) + //printf("Update: (%d,%d) %x\n", delta.u.data.x, delta.u.data.y, delta.u.data.buttons); + + rodent->update(&delta); +} + +static void smoothdata(mouse_info_t *delta) { + int xa, ya; /* X and Y averages */ + int x, y; + int sensitivity, xsensitivity, ysensitivity; + + if (synaptics.xaverage == 0) + synaptics.xaverage = synaptics.x; + if (synaptics.yaverage == 0) + synaptics.yaverage = synaptics.y; + + xa = synaptics.xaverage; + ya = synaptics.yaverage; + + synaptics.xaverage = (xa + synaptics.x) / 2; + synaptics.yaverage = (ya + synaptics.y) / 2; + + xsensitivity = (synaptics.xaverage - xa); + if (xsensitivity < 0) + xsensitivity = -xsensitivity; + ysensitivity = (synaptics.yaverage - ya); + if (ysensitivity < 0) + ysensitivity = -ysensitivity; + + sensitivity = (xsensitivity & ysensitivity) + 1; + + if ((synaptics.x > LOW_SPEED_THRESHOLD || synaptics.x < -LOW_SPEED_THRESHOLD) + || (synaptics.y > LOW_SPEED_THRESHOLD || synaptics.y < -LOW_SPEED_THRESHOLD)) { + synaptics.x = (synaptics.x + synaptics.oldx * 3) / 4; + synaptics.y = (synaptics.y + synaptics.oldy * 3) / 4; + + delta->u.data.x = (synaptics.x - synaptics.oldx) * 10 / 85; + delta->u.data.y = (synaptics.y - synaptics.oldy) * 10 / 85; + } else { + if (synaptics.x < -MIN_MOVEMENT) + delta->u.data.x = -1; + else if (synaptics.x > MIN_MOVEMENT) + delta->u.data.x = 1; + else + delta->u.data.x = 0; + + if (synaptics.y < -MIN_MOVEMENT) + delta->u.data.y = -1; + else if (synaptics.y > MIN_MOVEMENT) + delta->u.data.y = 1; + else + delta->u.data.y = 0; + } + + synaptics.squelch += sensitivity; + + if (synaptics.squelch < SQUELCH_LEVEL) { + delta->u.data.x = 0; + delta->u.data.y = 0; + } else + synaptics.squelch = 0; + + //printf("(movement) (%d, %d) (%02x)\n", (synaptics.x - synaptics.oldx), synaptics.y - synaptics.oldy, synaptics.buttons); +} + +void guestdata(char *packet, rodent_t *rodent) { + synaptics.x = (packet[1] & 0x10) ? packet[4] : packet[4]; + synaptics.y = (packet[1] & 0x20) ? packet[5] : packet[5]; + synaptics.z = 0; + + synaptics.guestbuttons = 0; + if (packet[1] & 0x01) + synaptics.guestbuttons |= MOUSE_BUTTON(1); + if (packet[1] & 0x02) + synaptics.guestbuttons |= MOUSE_BUTTON(3); + if (packet[1] & 0x04) + synaptics.guestbuttons |= MOUSE_BUTTON(2); + + //printf("(nipple) (%d, %d) W:%u Z:%u (%02x)\n", synaptics.x, synaptics.y, synaptics.w, synaptics.z, synaptics.buttons); +} + +void touchpaddata(char *packet, rodent_t *rodent) { + synaptics.x = SYNAPTICS_X; + synaptics.y = SYNAPTICS_Y; + + synaptics.touchbuttons = 0; + + if (packet[0] & 0x01) + synaptics.touchbuttons |= MOUSE_BUTTON(1); + if (packet[0] & 0x02) + synaptics.touchbuttons |= MOUSE_BUTTON(3); + + /* Single fingers are 4 <= w <= 8 */ + if ((synaptics.w >= 4 && synaptics.w <= 8) + && (synaptics.z >= TOUCH_THRESHOLD && synaptics.z < 200)) { + + if (rodent->verbose) + printf("Single finger\n"); + + if (synaptics.tap > 0) { + /* we tapped last time we had a finger down, holdclick */ + if ((synaptics.finger == 0) && (timecmplt(&synaptics.lastfingertime, TAP_TIMEOUT))) + synaptics.clickdrag = MOUSE_BUTTON(1); + + if (synaptics.clickdrag) + synaptics.touchbuttons |= synaptics.clickdrag; + } + + if (synaptics.finger == 0) { + synaptics.finger = 1; + gettimeofday(&synaptics.lastfingertime, NULL); + } else { + synaptics.drag = 1; + } + + //printf("(touchpad) (%d, %d) W