summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryokota <yokota@FreeBSD.org>2000-03-18 15:21:40 +0000
committeryokota <yokota@FreeBSD.org>2000-03-18 15:21:40 +0000
commitb91cbcb4f136bbc6c178bf362bc909c1f1dc8631 (patch)
treed80e1686adb1efb88325c6782baea25117934aec
parent1385bc5aceee9e021f47fd7a55cb832c8f106d70 (diff)
downloadFreeBSD-src-b91cbcb4f136bbc6c178bf362bc909c1f1dc8631.zip
FreeBSD-src-b91cbcb4f136bbc6c178bf362bc909c1f1dc8631.tar.gz
- Add Support for the following PS/2 mice:
- Microsoft IntelliMouse Explorer: 2 buttons on top, 2 side buttons and a wheel which also acts as the middle button. The mouse is recognized as "IntelliMouse Explorer". - Genius NetScroll Optical: 2 buttons on top, 2 side buttons and a wheel which also acts as the middle button. The mouse is recognized as "NetMouse/NetScroll Optical". - MouseSystems SmartScroll Mouse (OEM from Genius?): 3 buttons on top, 1 side button and a wheel. The mouse is recognized as Genius "NetScroll". - IBM ScrollPoint: 2 buttons on top and a stick between the buttons. The stick can perform "horizontal scroll" in W*ndows environment. The horizontal movement of the stick is detected. It is currently mapped to the Z axis movement in the same way as the first wheel. The mouse is recognized as "MouseMan+", as it is considered to be a variation of MouseMan. - A4 Tech 4D and 4D+ mice. These mice have two wheels! The movement of the second wheel is reported as the Z axis movement in the same way as the first wheel. These mice are recognized as "4D Mouse" and "4D+ Mouse". - Tweak IntelliMouse support code a bit so that less-than-compatible wheel mice can work properly with the psm driver. - Add driver configuration flags which correspond to the kernel options PSM_HOOKRESUME and PSM_RESETAFTERSUSPEND, so that we don't need to recompile the kernel when we need these functions. - Properly keep track of the irq resource. - Add a watchdog timer in case interrupts are lost (experimental). - Add `detach' function (experimental).
-rw-r--r--sys/alpha/include/mouse.h48
-rw-r--r--sys/dev/atkbdc/atkbdcreg.h3
-rw-r--r--sys/dev/atkbdc/psm.c482
-rw-r--r--sys/dev/kbd/atkbdcreg.h3
-rw-r--r--sys/i386/include/mouse.h48
-rw-r--r--sys/isa/psm.c482
-rw-r--r--sys/sys/mouse.h48
7 files changed, 928 insertions, 186 deletions
diff --git a/sys/alpha/include/mouse.h b/sys/alpha/include/mouse.h
index a08d027..1f9d63b 100644
--- a/sys/alpha/include/mouse.h
+++ b/sys/alpha/include/mouse.h
@@ -117,6 +117,9 @@ typedef struct mousehw {
#define MOUSE_MODEL_MOUSEMANPLUS 7
#define MOUSE_MODEL_KIDSPAD 8
#define MOUSE_MODEL_VERSAPAD 9
+#define MOUSE_MODEL_EXPLORER 10
+#define MOUSE_MODEL_4D 11
+#define MOUSE_MODEL_4DPLUS 12
typedef struct mousemode {
int protocol; /* MOUSE_PROTO_XXX */
@@ -129,6 +132,16 @@ typedef struct mousemode {
} mousemode_t;
/* protocol */
+/*
+ * Serial protocols:
+ * Microsoft, MouseSystems, Logitech, MM series, MouseMan, Hitachi Tablet,
+ * GlidePoint, IntelliMouse, Thinking Mouse, MouseRemote, Kidspad,
+ * VersaPad
+ * Bus mouse protocols:
+ * bus, InPort
+ * PS/2 mouse protocol:
+ * PS/2
+ */
#define MOUSE_PROTO_UNKNOWN (-1)
#define MOUSE_PROTO_MS 0 /* Microsoft Serial, 3 bytes */
#define MOUSE_PROTO_MSC 1 /* Mouse Systems, 5 bytes */
@@ -194,7 +207,7 @@ typedef struct mousevar {
/* MS IntelliMouse (variant of MS Serial) */
#define MOUSE_INTELLI_PACKETSIZE 4
-#define MOUSE_INTELLI_BUTTON2DOWN 0x10 /* middle button the 4th byte */
+#define MOUSE_INTELLI_BUTTON2DOWN 0x10 /* middle button in the 4th byte */
/* Mouse Systems Corp. mouse data packet */
#define MOUSE_MSC_PACKETSIZE 5
@@ -229,16 +242,34 @@ typedef struct mousevar {
* Yes! this is the same bit
* as SYNC!
*/
-#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10 /* 4th button on MouseMan+ */
-#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
#define MOUSE_PS2_XNEG 0x10
#define MOUSE_PS2_YNEG 0x20
#define MOUSE_PS2_XOVERFLOW 0x40
#define MOUSE_PS2_YOVERFLOW 0x80
-#define MOUSE_PS2PLUS_ZNEG 0x08 /* MouseMan+ negative wheel movement */
+
+/* Logitech MouseMan+ (PS/2) data packet (PS/2++ protocol) */
#define MOUSE_PS2PLUS_SYNCMASK 0x48
#define MOUSE_PS2PLUS_SYNC 0x48
+#define MOUSE_PS2PLUS_ZNEG 0x08 /* sign bit */
+#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10 /* 4th button on MouseMan+ */
+#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
+
+/* IBM ScrollPoint (PS/2) also uses PS/2++ protocol */
+#define MOUSE_SPOINT_ZNEG 0x80 /* sign bits */
+#define MOUSE_SPOINT_WNEG 0x08
+
+/* MS IntelliMouse (PS/2) data packet */
+#define MOUSE_PS2INTELLI_PACKETSIZE 4
+/* some compatible mice have additional buttons */
+#define MOUSE_PS2INTELLI_BUTTON4DOWN 0x40
+#define MOUSE_PS2INTELLI_BUTTON5DOWN 0x80
+
+/* MS IntelliMouse Explorer (PS/2) data packet (variation of IntelliMouse) */
+#define MOUSE_EXPLORER_ZNEG 0x08 /* sign bit */
+/* IntelliMouse Explorer has additional button data in the fourth byte */
+#define MOUSE_EXPLORER_BUTTON4DOWN 0x10
+#define MOUSE_EXPLORER_BUTTON5DOWN 0x20
/* Interlink VersaPad (serial I/F) data packet */
#define MOUSE_VERSA_PACKETSIZE 6
@@ -262,6 +293,15 @@ typedef struct mousevar {
#define MOUSE_PS2VERSA_BUTTON3DOWN 0x01 /* right */
#define MOUSE_PS2VERSA_TAP 0x02
+/* A4 Tech 4D Mouse (PS/2) data packet */
+#define MOUSE_4D_PACKETSIZE 3
+#define MOUSE_4D_WHEELBITS 0xf0
+
+/* A4 Tech 4D+ Mouse (PS/2) data packet */
+#define MOUSE_4DPLUS_PACKETSIZE 3
+#define MOUSE_4DPLUS_ZNEG 0x04 /* sign bit */
+#define MOUSE_4DPLUS_BUTTON4DOWN 0x08
+
/* sysmouse extended data packet */
/*
* /dev/sysmouse sends data in two formats, depending on the protocol
diff --git a/sys/dev/atkbdc/atkbdcreg.h b/sys/dev/atkbdc/atkbdcreg.h
index d01489e..164f6c1 100644
--- a/sys/dev/atkbdc/atkbdcreg.h
+++ b/sys/dev/atkbdc/atkbdcreg.h
@@ -132,6 +132,9 @@
#define PSM_MOUSE_ID 0
#define PSM_BALLPOINT_ID 2
#define PSM_INTELLI_ID 3
+#define PSM_EXPLORER_ID 4
+#define PSM_4DMOUSE_ID 6
+#define PSM_4DPLUS_ID 8
#ifdef _KERNEL
diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c
index e702d04..409d2a1 100644
--- a/sys/dev/atkbdc/psm.c
+++ b/sys/dev/atkbdc/psm.c
@@ -95,20 +95,6 @@
#define PSM_DEBUG 0 /* logging: 0: none, 1: brief, 2: verbose */
#endif
-/* features */
-
-/* #define PSM_HOOKRESUME hook the system resume event */
-/* #define PSM_RESETAFTERSUSPEND reset the device at the resume event */
-
-#ifdef PSM_HOOKAPM
-#undef PSM_HOOKRESUME
-#define PSM_HOOKRESUME 1
-#endif /* PSM_HOOKAPM */
-
-#ifndef PSM_HOOKRESUME
-#undef PSM_RESETAFTERSUSPEND
-#endif /* PSM_HOOKRESUME */
-
/* end of driver specific options */
/* input queue */
@@ -157,7 +143,8 @@ struct psm_softc { /* Driver status information */
int config; /* driver configuration flags */
int flags; /* other flags */
KBDC kbdc; /* handle to access the keyboard controller */
- int addr; /* I/O port address */
+ struct resource *intr; /* IRQ resource */
+ void *ih; /* interrupt handle */
mousehw_t hw; /* hardware information */
mousemode_t mode; /* operation mode */
mousemode_t dflt_mode; /* default operation mode */
@@ -168,6 +155,10 @@ struct psm_softc { /* Driver status information */
int button; /* the latest button state */
int xold; /* previous absolute X position */
int yold; /* previous absolute Y position */
+ int watchdog; /* watchdog timer flag */
+ struct callout_handle callout; /* watchdog timer call out */
+ dev_t dev;
+ dev_t bdev;
};
devclass_t psm_devclass;
#define PSM_SOFTC(unit) ((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
@@ -185,6 +176,8 @@ devclass_t psm_devclass;
#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_FLAGS (PSM_CONFIG_RESOLUTION \
| PSM_CONFIG_ACCEL \
@@ -192,7 +185,9 @@ devclass_t psm_devclass;
| PSM_CONFIG_NOIDPROBE \
| PSM_CONFIG_NORESET \
| PSM_CONFIG_FORCETAP \
- | PSM_CONFIG_IGNPORTERROR)
+ | PSM_CONFIG_IGNPORTERROR \
+ | PSM_CONFIG_HOOKRESUME \
+ | PSM_CONFIG_INITAFTERSUSPEND)
/* other flags (flags) */
#define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */
@@ -223,6 +218,7 @@ typedef int packetfunc_t __P((struct psm_softc *, unsigned char *,
/* function prototypes */
static int psmprobe __P((device_t));
static int psmattach __P((device_t));
+static int psmdetach __P((device_t));
static int psmresume __P((device_t));
static d_open_t psmopen;
@@ -238,19 +234,16 @@ static int get_aux_id __P((KBDC));
static int set_mouse_sampling_rate __P((KBDC, int));
static int set_mouse_scaling __P((KBDC, int));
static int set_mouse_resolution __P((KBDC, int));
-#ifdef PSM_RESETAFTERSUSPEND
static int set_mouse_mode __P((KBDC));
-#endif /* PSM_RESETAFTERSUSPEND */
static int get_mouse_buttons __P((KBDC));
static int is_a_mouse __P((int));
static void recover_from_error __P((KBDC));
static int restore_controller __P((KBDC, int));
-#ifdef PSM_RESETAFTERSUSPEND
static int reinitialize __P((int, mousemode_t *));
-#endif
static int doopen __P((int, int));
-static char *model_name(int);
-static void psmintr(void*);
+static char *model_name __P((int));
+static void psmintr __P((void *));
+static void psmtimeout __P((void *));
/* vendor specific features */
typedef int probefunc_t __P((struct psm_softc *));
@@ -260,7 +253,10 @@ static probefunc_t enable_groller;
static probefunc_t enable_gmouse;
static probefunc_t enable_aglide;
static probefunc_t enable_kmouse;
+static probefunc_t enable_msexplorer;
static probefunc_t enable_msintelli;
+static probefunc_t enable_4dmouse;
+static probefunc_t enable_4dplus;
static probefunc_t enable_mmanplus;
static probefunc_t enable_versapad;
static int tame_mouse __P((struct psm_softc *, mousestatus_t *, unsigned char *));
@@ -271,18 +267,28 @@ static struct {
int packetsize;
probefunc_t *probefunc;
} vendortype[] = {
+ /*
+ * WARNING: the order of probe is very important. Don't mess it
+ * unless you know what you are doing.
+ */
{ MOUSE_MODEL_NET, /* Genius NetMouse */
- 0xc8, MOUSE_INTELLI_PACKETSIZE, enable_gmouse, },
+ 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse, },
{ MOUSE_MODEL_NETSCROLL, /* Genius NetScroll */
0xc8, 6, enable_groller, },
- { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
- 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
{ MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */
0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus, },
+ { MOUSE_MODEL_EXPLORER, /* Microsoft IntelliMouse Explorer */
+ 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer, },
+ { MOUSE_MODEL_4D, /* A4 Tech 4D Mouse */
+ 0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse, },
+ { MOUSE_MODEL_4DPLUS, /* A4 Tech 4D+ Mouse */
+ 0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus, },
+ { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
+ 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli, },
+ { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
+ 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
{ MOUSE_MODEL_THINK, /* Kensignton ThinkingMouse */
0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, },
- { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
- 0xc8, MOUSE_INTELLI_PACKETSIZE, enable_msintelli, },
{ MOUSE_MODEL_VERSAPAD, /* Interlink electronics VersaPad */
0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, },
{ MOUSE_MODEL_GENERIC,
@@ -295,6 +301,7 @@ static device_method_t psm_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, psmprobe),
DEVMETHOD(device_attach, psmattach),
+ DEVMETHOD(device_detach, psmdetach),
DEVMETHOD(device_resume, psmresume),
{ 0, 0 }
@@ -306,6 +313,14 @@ static driver_t psm_driver = {
sizeof(struct psm_softc),
};
+#if notyet
+static struct isa_pnp_id psm_ids[] = {
+ { 0x130fd041, "PS/2 mouse port" }, /* PNP0F13 */
+ { 0x1303d041, "PS/2 port" }, /* PNP0313, XXX */
+ { 0 }
+};
+#endif
+
#define CDEV_MAJOR 21
static struct cdevsw psm_cdevsw = {
@@ -461,7 +476,6 @@ set_mouse_resolution(KBDC kbdc, int val)
return ((res == PSM_ACK) ? val : -1);
}
-#ifdef PSM_RESETAFTERSUSPEND
/*
* NOTE: once `set_mouse_mode()' is called, the mouse device must be
* re-enabled by calling `enable_aux_dev()'
@@ -477,8 +491,6 @@ set_mouse_mode(KBDC kbdc)
return (res == PSM_ACK);
}
-#endif /* PSM_RESETAFTERSUSPEND */
-
static int
get_mouse_buttons(KBDC kbdc)
@@ -517,6 +529,7 @@ is_a_mouse(int id)
PSM_MOUSE_ID, /* mouse */
PSM_BALLPOINT_ID, /* ballpoint device */
PSM_INTELLI_ID, /* Intellimouse */
+ PSM_EXPLORER_ID, /* Intellimouse Explorer */
-1 /* end of table */
};
int i;
@@ -537,13 +550,16 @@ model_name(int model)
int model_code;
char *model_name;
} models[] = {
- { MOUSE_MODEL_NETSCROLL, "NetScroll Mouse" },
- { MOUSE_MODEL_NET, "NetMouse" },
+ { MOUSE_MODEL_NETSCROLL, "NetScroll" },
+ { MOUSE_MODEL_NET, "NetMouse/NetScroll Optical" },
{ MOUSE_MODEL_GLIDEPOINT, "GlidePoint" },
{ MOUSE_MODEL_THINK, "ThinkingMouse" },
{ MOUSE_MODEL_INTELLI, "IntelliMouse" },
{ MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" },
{ MOUSE_MODEL_VERSAPAD, "VersaPad" },
+ { MOUSE_MODEL_EXPLORER, "IntelliMouse Explorer" },
+ { MOUSE_MODEL_4D, "4D Mouse" },
+ { MOUSE_MODEL_4DPLUS, "4D+ Mouse" },
{ MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" },
{ MOUSE_MODEL_UNKNOWN, NULL },
};
@@ -591,13 +607,14 @@ restore_controller(KBDC kbdc, int command_byte)
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;
}
}
-#ifdef PSM_RESETAFTERSUSPEND
/*
* Re-initialize the aux port and device. The aux port must be enabled
* and its interrupt must be disabled before calling this routine.
@@ -704,7 +721,6 @@ reinitialize(int unit, mousemode_t *mode)
return TRUE;
}
-#endif /* PSM_RESETAFTERSUSPEND */
static int
doopen(int unit, int command_byte)
@@ -756,6 +772,10 @@ doopen(int unit, int command_byte)
return (EIO);
}
+ /* start the watchdog timer */
+ sc->watchdog = FALSE;
+ sc->callout = timeout(psmtimeout, (void *)unit, hz*2);
+
return (0);
}
@@ -773,22 +793,38 @@ psmprobe(device_t dev)
{
int unit = device_get_unit(dev);
struct psm_softc *sc = device_get_softc(dev);
- uintptr_t port;
+ uintptr_t irq;
uintptr_t flags;
int stat[3];
int command_byte;
int mask;
+ int rid;
int i;
#if 0
kbdc_debug(TRUE);
#endif
- BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_PORT, &port);
+
+#if notyet
+ /* check PnP IDs */
+ if (XXX_PNP_PROBE(device_get_parent(dev), dev, psm_ids) == ENXIO)
+ return ENXIO;
+#endif
+
+ BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
- sc->addr = port;
- sc->kbdc = kbdc_open(sc->addr);
+ sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
sc->config = flags & 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;
@@ -939,6 +975,9 @@ psmprobe(device_t dev)
break;
case PSM_MOUSE_ID:
case PSM_INTELLI_ID:
+ case PSM_EXPLORER_ID:
+ case PSM_4DMOUSE_ID:
+ case PSM_4DPLUS_ID:
sc->hw.type = MOUSE_MOUSE;
break;
default:
@@ -1044,6 +1083,18 @@ psmprobe(device_t dev)
endprobe(ENXIO);
}
+ /* see if IRQ is available */
+ rid = 0;
+ sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
+ RF_ACTIVE);
+ if (sc->intr == NULL) {
+ printf("psm%d: unable to allocate the IRQ resource (%d).\n",
+ unit, irq);
+ endprobe(ENXIO);
+ } else {
+ bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
+ }
+
/* done */
kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
kbdc_lock(sc->kbdc, FALSE);
@@ -1055,20 +1106,36 @@ psmattach(device_t dev)
{
int unit = device_get_unit(dev);
struct psm_softc *sc = device_get_softc(dev);
- void *ih;
- struct resource *res;
uintptr_t irq;
- int zero = 0;
+ int error;
+ int rid;
if (sc == NULL) /* shouldn't happen */
return (ENXIO);
/* Setup initial state */
sc->state = PSM_VALID;
+ callout_handle_init(&sc->callout);
+
+ /* Setup our interrupt handler */
+ rid = 0;
+ BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
+ sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
+ RF_ACTIVE);
+ if (sc->intr == NULL)
+ return (ENXIO);
+ error = BUS_SETUP_INTR(device_get_parent(dev), 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 */
- make_dev(&psm_cdevsw, PSM_MKMINOR(unit, FALSE), 0, 0, 0666, "psm%d", unit);
- make_dev(&psm_cdevsw, PSM_MKMINOR(unit, TRUE), 0, 0, 0666, "bpsm%d", unit);
+ 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);
if (!verbose) {
printf("psm%d: model %s, device ID %d\n",
@@ -1086,16 +1153,30 @@ psmattach(device_t dev)
if (bootverbose)
--verbose;
- BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
- res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
- RF_SHAREABLE | RF_ACTIVE);
- BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY,
- psmintr, sc, &ih);
-
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 = 0;
+ BUS_TEARDOWN_INTR(device_get_parent(dev), 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(dev_t dev, int flag, int fmt, struct proc *p)
{
int unit = PSM_UNIT(dev);
@@ -1121,6 +1202,7 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p)
sc->rsel.si_pid = 0;
sc->mode.level = sc->dflt_mode.level;
sc->mode.protocol = sc->dflt_mode.protocol;
+ sc->watchdog = FALSE;
/* flush the event queue */
sc->queue.count = 0;
@@ -1206,7 +1288,7 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
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",
- PSM_UNIT(dev));
+ 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
@@ -1216,6 +1298,10 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
}
splx(s);
+ /* stop the watchdog timer */
+ untimeout(psmtimeout, (void *)unit, sc->callout);
+ callout_handle_init(&sc->callout);
+
/* remove anything left in the output buffer */
empty_aux_buffer(sc->kbdc, 10);
@@ -1229,12 +1315,12 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
* hereafter.
*/
log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n",
- PSM_UNIT(dev));
+ unit);
}
if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n",
- PSM_UNIT(dev));
+ unit);
}
if (!set_controller_command_byte(sc->kbdc,
@@ -1245,7 +1331,7 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
* we shall ignore this error; see the above comment.
*/
log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n",
- PSM_UNIT(dev));
+ unit);
}
/* remove anything left in the output buffer */
@@ -1738,6 +1824,23 @@ psmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
}
static void
+psmtimeout(void *arg)
+{
+ struct psm_softc *sc;
+ int unit;
+
+ unit = (int)arg;
+ sc = devclass_get_softc(psm_devclass, unit);
+ if (sc->watchdog) {
+ if (verbose >= 4)
+ log(LOG_DEBUG, "psm%d: lost interrupt?\n", unit);
+ psmintr(sc);
+ }
+ sc->watchdog = TRUE;
+ sc->callout = timeout(psmtimeout, (void *)unit, hz);
+}
+
+static void
psmintr(void *arg)
{
/*
@@ -1805,11 +1908,9 @@ psmintr(void *arg)
/*
* A kludge for Kensington device!
* The MSB of the horizontal count appears to be stored in
- * a strange place. This kludge doesn't affect other mice
- * because the bit is the overflow bit which is, in most cases,
- * expected to be zero when we reach here. XXX
+ * a strange place.
*/
- if (sc->hw.model != MOUSE_MODEL_VERSAPAD)
+ if (sc->hw.model == MOUSE_MODEL_THINK)
sc->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
/* ignore the overflow bits... */
@@ -1824,10 +1925,38 @@ psmintr(void *arg)
switch (sc->hw.model) {
+ case MOUSE_MODEL_EXPLORER:
+ /*
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * byte 1: oy ox sy sx 1 M R L
+ * byte 2: x x x x x x x x
+ * byte 3: y y y y y y y y
+ * byte 4: * * S2 S1 s d2 d1 d0
+ *
+ * L, M, R, S1, S2: left, middle, right and side buttons
+ * s: wheel data sign bit
+ * d2-d0: wheel data
+ */
+ z = (sc->ipacket[3] & MOUSE_EXPLORER_ZNEG)
+ ? (sc->ipacket[3] & 0x0f) - 16 : (sc->ipacket[3] & 0x0f);
+ ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN)
+ ? MOUSE_BUTTON4DOWN : 0;
+ ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN)
+ ? MOUSE_BUTTON5DOWN : 0;
+ break;
+
case MOUSE_MODEL_INTELLI:
case MOUSE_MODEL_NET:
/* wheel data is in the fourth byte */
z = (char)sc->ipacket[3];
+ /* some mice may send 7 when there is no Z movement?! XXX */
+ if ((z >= 7) || (z <= -7))
+ z = 0;
+ /* some compatible mice have additional buttons */
+ ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN)
+ ? MOUSE_BUTTON4DOWN : 0;
+ ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN)
+ ? MOUSE_BUTTON5DOWN : 0;
break;
case MOUSE_MODEL_MOUSEMANPLUS:
@@ -1880,18 +2009,40 @@ psmintr(void *arg)
? MOUSE_BUTTON5DOWN : 0;
break;
case 2:
- /* this packet type is reserved, and currently ignored */
- /* FALL THROUGH */
+ /* this packet type is reserved by Logitech... */
+ /*
+ * IBM ScrollPoint Mouse uses this packet type to
+ * encode both vertical and horizontal scroll movement.
+ */
+ x = y = 0;
+ /* horizontal count */
+ if (sc->ipacket[2] & 0x0f)
+ z = (sc->ipacket[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
+ /* vertical count */
+ if (sc->ipacket[2] & 0xf0)
+ z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
+#if 0
+ /* vertical count */
+ z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG)
+ ? ((sc->ipacket[2] >> 4) & 0x0f) - 16
+ : ((sc->ipacket[2] >> 4) & 0x0f);
+ /* horizontal count */
+ w = (sc->ipacket[2] & MOUSE_SPOINT_WNEG)
+ ? (sc->ipacket[2] & 0x0f) - 16
+ : (sc->ipacket[2] & 0x0f);
+#endif
+ break;
case 0:
/* device type packet - shouldn't happen */
/* FALL THROUGH */
default:
x = y = 0;
ms.button = ms.obutton;
- log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
- "0x%02x 0x%02x 0x%02x\n",
- MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
- sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
+ if (bootverbose)
+ log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
+ "0x%02x 0x%02x 0x%02x\n",
+ MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
+ sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
break;
}
} else {
@@ -1906,9 +2057,11 @@ psmintr(void *arg)
break;
case MOUSE_MODEL_NETSCROLL:
- /* three addtional bytes encode button and wheel events */
- ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN)
+ /* three addtional bytes encode buttons and wheel events */
+ ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN)
? MOUSE_BUTTON4DOWN : 0;
+ ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON1DOWN)
+ ? MOUSE_BUTTON5DOWN : 0;
z = (sc->ipacket[3] & MOUSE_PS2_XNEG)
? sc->ipacket[4] - 256 : sc->ipacket[4];
break;
@@ -1973,6 +2126,60 @@ psmintr(void *arg)
| ((y < 0) ? MOUSE_PS2_YNEG : 0);
break;
+ case MOUSE_MODEL_4D:
+ /*
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * byte 1: s2 d2 s1 d1 1 M R L
+ * byte 2: sx x x x x x x x
+ * byte 3: sy y y y y y y y
+ *
+ * s1: wheel 1 direction
+ * d1: wheel 1 data
+ * s2: wheel 2 direction
+ * d2: wheel 2 data
+ */
+ x = (sc->ipacket[1] & 0x80) ? sc->ipacket[1] - 256 : sc->ipacket[1];
+ y = (sc->ipacket[2] & 0x80) ? sc->ipacket[2] - 256 : sc->ipacket[2];
+ switch (c & MOUSE_4D_WHEELBITS) {
+ case 0x10:
+ z = 1;
+ break;
+ case 0x30:
+ z = -1;
+ break;
+ case 0x40: /* 2nd wheel turning right XXX */
+ z = 2;
+ break;
+ case 0xc0: /* 2nd wheel turning left XXX */
+ z = -2;
+ break;
+ }
+ break;
+
+ case MOUSE_MODEL_4DPLUS:
+ if ((x < 16 - 256) && (y < 16 - 256)) {
+ /*
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * byte 1: 0 0 1 1 1 M R L
+ * byte 2: 0 0 0 0 1 0 0 0
+ * byte 3: 0 0 0 0 S s d1 d0
+ *
+ * L, M, R, S: left, middle, right and side buttons
+ * s: wheel data sign bit
+ * d1-d0: wheel data
+ */
+ x = y = 0;
+ if (sc->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
+ ms.button |= MOUSE_BUTTON4DOWN;
+ z = (sc->ipacket[2] & MOUSE_4DPLUS_ZNEG)
+ ? ((sc->ipacket[2] & 0x07) - 8)
+ : (sc->ipacket[2] & 0x07) ;
+ } else {
+ /* preserve previous button states */
+ ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
+ }
+ break;
+
case MOUSE_MODEL_GENERIC:
default:
break;
@@ -2012,6 +2219,8 @@ psmintr(void *arg)
sc->status.button = ms.button;
sc->button = ms.button;
+ sc->watchdog = FALSE;
+
/* queue data */
if (sc->queue.count + sc->inputbytes < sizeof(sc->queue.buf)) {
l = min(sc->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail);
@@ -2089,7 +2298,7 @@ enable_lcordless(struct psm_softc *sc)
}
#endif /* notyet */
-/* Genius NetScroll Mouse */
+/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
static int
enable_groller(struct psm_softc *sc)
{
@@ -2120,13 +2329,12 @@ enable_groller(struct psm_softc *sc)
return FALSE;
if ((status[1] != '3') || (status[2] != 'D'))
return FALSE;
- /* FIXME!! */
- sc->hw.buttons = get_mouse_buttons(sc->kbdc);
+ /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
sc->hw.buttons = 4;
return TRUE;
}
-/* Genius NetMouse/NetMouse Pro */
+/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
static int
enable_gmouse(struct psm_softc *sc)
{
@@ -2226,7 +2434,7 @@ enable_kmouse(struct psm_softc *sc)
return TRUE;
}
-/* Logitech MouseMan+/FirstMouse+ */
+/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
static int
enable_mmanplus(struct psm_softc *sc)
{
@@ -2240,6 +2448,11 @@ enable_mmanplus(struct psm_softc *sc)
int i;
/* the special sequence to enable the fourth button and the roller. */
+ /*
+ * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
+ * must be called exactly three times since the last RESET command
+ * before this sequence. XXX
+ */
for (i = 0; i < sizeof(res)/sizeof(res[0]); ++i) {
if (res[i] < 0) {
if (!set_mouse_scaling(kbdc, 1))
@@ -2262,7 +2475,7 @@ enable_mmanplus(struct psm_softc *sc)
* byte 3: m7 m6 m5 m4 m3 m2 m1 m0
*
* p3-p0: packet type: 0
- * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51,...
+ * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51, ScrollPoint:0x58...
*/
/* check constant bits */
if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
@@ -2288,6 +2501,31 @@ enable_mmanplus(struct psm_softc *sc)
return TRUE;
}
+/* MS IntelliMouse Explorer */
+static int
+enable_msexplorer(struct psm_softc *sc)
+{
+ static unsigned char rate[] = { 200, 200, 80, };
+ KBDC kbdc = sc->kbdc;
+ int id;
+ int i;
+
+ /* the special sequence to enable the extra buttons and the roller. */
+ for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
+ if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+ return FALSE;
+ }
+ /* the device will give the genuine ID only after the above sequence */
+ id = get_aux_id(kbdc);
+ if (id != PSM_EXPLORER_ID)
+ return FALSE;
+
+ sc->hw.hwid = id;
+ sc->hw.buttons = 5; /* IntelliMouse Explorer XXX */
+
+ return TRUE;
+}
+
/* MS IntelliMouse */
static int
enable_msintelli(struct psm_softc *sc)
@@ -2318,6 +2556,70 @@ enable_msintelli(struct psm_softc *sc)
return TRUE;
}
+/* A4 Tech 4D Mouse */
+static int
+enable_4dmouse(struct psm_softc *sc)
+{
+ /*
+ * Newer wheel mice from A4 Tech may use the 4D+ protocol.
+ */
+
+ static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
+ KBDC kbdc = sc->kbdc;
+ int id;
+ int i;
+
+ for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
+ if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+ return FALSE;
+ }
+ id = get_aux_id(kbdc);
+ /*
+ * WinEasy 4D: 6
+ * Cable-Free 4D: 8 (4DPLUS)
+ * 4 Way ScrollMouse 4D+: 8 (4DPLUS)
+ */
+ if (id != PSM_4DMOUSE_ID)
+ return FALSE;
+
+ sc->hw.hwid = id;
+ sc->hw.buttons = 3; /* XXX some 4D mice have 4? */
+
+ return TRUE;
+}
+
+/* A4 Tech 4D+ Mouse */
+static int
+enable_4dplus(struct psm_softc *sc)
+{
+ /*
+ * Newer wheel mice from A4 Tech seem to use this protocol.
+ * Older models are recognized as either 4D Mouse or IntelliMouse.
+ */
+ KBDC kbdc = sc->kbdc;
+ int id;
+
+ /*
+ * enable_4dmouse() already issued the following ID sequence...
+ static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
+ int i;
+
+ for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
+ if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+ return FALSE;
+ }
+ */
+
+ id = get_aux_id(kbdc);
+ if (id != PSM_4DPLUS_ID)
+ return FALSE;
+
+ sc->hw.hwid = id;
+ sc->hw.buttons = 4; /* XXX */
+
+ return TRUE;
+}
+
/* Interlink electronics VersaPad */
static int
enable_versapad(struct psm_softc *sc)
@@ -2337,13 +2639,14 @@ enable_versapad(struct psm_softc *sc)
return FALSE;
set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
+ sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
+
return TRUE; /* PS/2 absolute mode */
}
static int
psmresume(device_t dev)
{
-#ifdef PSM_HOOKRESUME
struct psm_softc *sc = device_get_softc(dev);
int unit = device_get_unit(dev);
int err = 0;
@@ -2353,11 +2656,19 @@ psmresume(device_t dev)
if (verbose >= 2)
log(LOG_NOTICE, "psm%d: system resume hook called.\n", unit);
+ if (!(sc->config & PSM_CONFIG_HOOKRESUME))
+ return (0);
+
/* 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 *)unit, 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);
@@ -2385,20 +2696,20 @@ psmresume(device_t dev)
}
sc->inputbytes = 0;
-#ifdef PSM_RESETAFTERSUSPEND
/* try to detect the aux device; are you still there? */
- if (reinitialize(unit, &sc->mode)) {
- /* 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! (psmresume).\n",
- unit);
- err = ENXIO;
+ if (sc->config & PSM_CONFIG_INITAFTERSUSPEND) {
+ if (reinitialize(unit, &sc->mode)) {
+ /* 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! (psmresume).\n",
+ unit);
+ err = ENXIO;
+ }
}
-#endif /* PSM_RESETAFTERSUSPEND */
splx(s);
/* restore the driver state */
@@ -2436,9 +2747,6 @@ psmresume(device_t dev)
log(LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit);
return (err);
-#else /* !PSM_HOOKRESUME */
- return (0);
-#endif /* PSM_HOOKRESUME */
}
DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
diff --git a/sys/dev/kbd/atkbdcreg.h b/sys/dev/kbd/atkbdcreg.h
index d01489e..164f6c1 100644
--- a/sys/dev/kbd/atkbdcreg.h
+++ b/sys/dev/kbd/atkbdcreg.h
@@ -132,6 +132,9 @@
#define PSM_MOUSE_ID 0
#define PSM_BALLPOINT_ID 2
#define PSM_INTELLI_ID 3
+#define PSM_EXPLORER_ID 4
+#define PSM_4DMOUSE_ID 6
+#define PSM_4DPLUS_ID 8
#ifdef _KERNEL
diff --git a/sys/i386/include/mouse.h b/sys/i386/include/mouse.h
index 12d49a2..670f2ae 100644
--- a/sys/i386/include/mouse.h
+++ b/sys/i386/include/mouse.h
@@ -116,6 +116,9 @@ typedef struct mousehw {
#define MOUSE_MODEL_MOUSEMANPLUS 7
#define MOUSE_MODEL_KIDSPAD 8
#define MOUSE_MODEL_VERSAPAD 9
+#define MOUSE_MODEL_EXPLORER 10
+#define MOUSE_MODEL_4D 11
+#define MOUSE_MODEL_4DPLUS 12
typedef struct mousemode {
int protocol; /* MOUSE_PROTO_XXX */
@@ -128,6 +131,16 @@ typedef struct mousemode {
} mousemode_t;
/* protocol */
+/*
+ * Serial protocols:
+ * Microsoft, MouseSystems, Logitech, MM series, MouseMan, Hitachi Tablet,
+ * GlidePoint, IntelliMouse, Thinking Mouse, MouseRemote, Kidspad,
+ * VersaPad
+ * Bus mouse protocols:
+ * bus, InPort
+ * PS/2 mouse protocol:
+ * PS/2
+ */
#define MOUSE_PROTO_UNKNOWN (-1)
#define MOUSE_PROTO_MS 0 /* Microsoft Serial, 3 bytes */
#define MOUSE_PROTO_MSC 1 /* Mouse Systems, 5 bytes */
@@ -193,7 +206,7 @@ typedef struct mousevar {
/* MS IntelliMouse (variant of MS Serial) */
#define MOUSE_INTELLI_PACKETSIZE 4
-#define MOUSE_INTELLI_BUTTON2DOWN 0x10 /* middle button the 4th byte */
+#define MOUSE_INTELLI_BUTTON2DOWN 0x10 /* middle button in the 4th byte */
/* Mouse Systems Corp. mouse data packet */
#define MOUSE_MSC_PACKETSIZE 5
@@ -228,16 +241,34 @@ typedef struct mousevar {
* Yes! this is the same bit
* as SYNC!
*/
-#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10 /* 4th button on MouseMan+ */
-#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
#define MOUSE_PS2_XNEG 0x10
#define MOUSE_PS2_YNEG 0x20
#define MOUSE_PS2_XOVERFLOW 0x40
#define MOUSE_PS2_YOVERFLOW 0x80
-#define MOUSE_PS2PLUS_ZNEG 0x08 /* MouseMan+ negative wheel movement */
+
+/* Logitech MouseMan+ (PS/2) data packet (PS/2++ protocol) */
#define MOUSE_PS2PLUS_SYNCMASK 0x48
#define MOUSE_PS2PLUS_SYNC 0x48
+#define MOUSE_PS2PLUS_ZNEG 0x08 /* sign bit */
+#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10 /* 4th button on MouseMan+ */
+#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
+
+/* IBM ScrollPoint (PS/2) also uses PS/2++ protocol */
+#define MOUSE_SPOINT_ZNEG 0x80 /* sign bits */
+#define MOUSE_SPOINT_WNEG 0x08
+
+/* MS IntelliMouse (PS/2) data packet */
+#define MOUSE_PS2INTELLI_PACKETSIZE 4
+/* some compatible mice have additional buttons */
+#define MOUSE_PS2INTELLI_BUTTON4DOWN 0x40
+#define MOUSE_PS2INTELLI_BUTTON5DOWN 0x80
+
+/* MS IntelliMouse Explorer (PS/2) data packet (variation of IntelliMouse) */
+#define MOUSE_EXPLORER_ZNEG 0x08 /* sign bit */
+/* IntelliMouse Explorer has additional button data in the fourth byte */
+#define MOUSE_EXPLORER_BUTTON4DOWN 0x10
+#define MOUSE_EXPLORER_BUTTON5DOWN 0x20
/* Interlink VersaPad (serial I/F) data packet */
#define MOUSE_VERSA_PACKETSIZE 6
@@ -261,6 +292,15 @@ typedef struct mousevar {
#define MOUSE_PS2VERSA_BUTTON3DOWN 0x01 /* right */
#define MOUSE_PS2VERSA_TAP 0x02
+/* A4 Tech 4D Mouse (PS/2) data packet */
+#define MOUSE_4D_PACKETSIZE 3
+#define MOUSE_4D_WHEELBITS 0xf0
+
+/* A4 Tech 4D+ Mouse (PS/2) data packet */
+#define MOUSE_4DPLUS_PACKETSIZE 3
+#define MOUSE_4DPLUS_ZNEG 0x04 /* sign bit */
+#define MOUSE_4DPLUS_BUTTON4DOWN 0x08
+
/* sysmouse extended data packet */
/*
* /dev/sysmouse sends data in two formats, depending on the protocol
diff --git a/sys/isa/psm.c b/sys/isa/psm.c
index e702d04..409d2a1 100644
--- a/sys/isa/psm.c
+++ b/sys/isa/psm.c
@@ -95,20 +95,6 @@
#define PSM_DEBUG 0 /* logging: 0: none, 1: brief, 2: verbose */
#endif
-/* features */
-
-/* #define PSM_HOOKRESUME hook the system resume event */
-/* #define PSM_RESETAFTERSUSPEND reset the device at the resume event */
-
-#ifdef PSM_HOOKAPM
-#undef PSM_HOOKRESUME
-#define PSM_HOOKRESUME 1
-#endif /* PSM_HOOKAPM */
-
-#ifndef PSM_HOOKRESUME
-#undef PSM_RESETAFTERSUSPEND
-#endif /* PSM_HOOKRESUME */
-
/* end of driver specific options */
/* input queue */
@@ -157,7 +143,8 @@ struct psm_softc { /* Driver status information */
int config; /* driver configuration flags */
int flags; /* other flags */
KBDC kbdc; /* handle to access the keyboard controller */
- int addr; /* I/O port address */
+ struct resource *intr; /* IRQ resource */
+ void *ih; /* interrupt handle */
mousehw_t hw; /* hardware information */
mousemode_t mode; /* operation mode */
mousemode_t dflt_mode; /* default operation mode */
@@ -168,6 +155,10 @@ struct psm_softc { /* Driver status information */
int button; /* the latest button state */
int xold; /* previous absolute X position */
int yold; /* previous absolute Y position */
+ int watchdog; /* watchdog timer flag */
+ struct callout_handle callout; /* watchdog timer call out */
+ dev_t dev;
+ dev_t bdev;
};
devclass_t psm_devclass;
#define PSM_SOFTC(unit) ((struct psm_softc*)devclass_get_softc(psm_devclass, unit))
@@ -185,6 +176,8 @@ devclass_t psm_devclass;
#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_FLAGS (PSM_CONFIG_RESOLUTION \
| PSM_CONFIG_ACCEL \
@@ -192,7 +185,9 @@ devclass_t psm_devclass;
| PSM_CONFIG_NOIDPROBE \
| PSM_CONFIG_NORESET \
| PSM_CONFIG_FORCETAP \
- | PSM_CONFIG_IGNPORTERROR)
+ | PSM_CONFIG_IGNPORTERROR \
+ | PSM_CONFIG_HOOKRESUME \
+ | PSM_CONFIG_INITAFTERSUSPEND)
/* other flags (flags) */
#define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */
@@ -223,6 +218,7 @@ typedef int packetfunc_t __P((struct psm_softc *, unsigned char *,
/* function prototypes */
static int psmprobe __P((device_t));
static int psmattach __P((device_t));
+static int psmdetach __P((device_t));
static int psmresume __P((device_t));
static d_open_t psmopen;
@@ -238,19 +234,16 @@ static int get_aux_id __P((KBDC));
static int set_mouse_sampling_rate __P((KBDC, int));
static int set_mouse_scaling __P((KBDC, int));
static int set_mouse_resolution __P((KBDC, int));
-#ifdef PSM_RESETAFTERSUSPEND
static int set_mouse_mode __P((KBDC));
-#endif /* PSM_RESETAFTERSUSPEND */
static int get_mouse_buttons __P((KBDC));
static int is_a_mouse __P((int));
static void recover_from_error __P((KBDC));
static int restore_controller __P((KBDC, int));
-#ifdef PSM_RESETAFTERSUSPEND
static int reinitialize __P((int, mousemode_t *));
-#endif
static int doopen __P((int, int));
-static char *model_name(int);
-static void psmintr(void*);
+static char *model_name __P((int));
+static void psmintr __P((void *));
+static void psmtimeout __P((void *));
/* vendor specific features */
typedef int probefunc_t __P((struct psm_softc *));
@@ -260,7 +253,10 @@ static probefunc_t enable_groller;
static probefunc_t enable_gmouse;
static probefunc_t enable_aglide;
static probefunc_t enable_kmouse;
+static probefunc_t enable_msexplorer;
static probefunc_t enable_msintelli;
+static probefunc_t enable_4dmouse;
+static probefunc_t enable_4dplus;
static probefunc_t enable_mmanplus;
static probefunc_t enable_versapad;
static int tame_mouse __P((struct psm_softc *, mousestatus_t *, unsigned char *));
@@ -271,18 +267,28 @@ static struct {
int packetsize;
probefunc_t *probefunc;
} vendortype[] = {
+ /*
+ * WARNING: the order of probe is very important. Don't mess it
+ * unless you know what you are doing.
+ */
{ MOUSE_MODEL_NET, /* Genius NetMouse */
- 0xc8, MOUSE_INTELLI_PACKETSIZE, enable_gmouse, },
+ 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse, },
{ MOUSE_MODEL_NETSCROLL, /* Genius NetScroll */
0xc8, 6, enable_groller, },
- { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
- 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
{ MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */
0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus, },
+ { MOUSE_MODEL_EXPLORER, /* Microsoft IntelliMouse Explorer */
+ 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer, },
+ { MOUSE_MODEL_4D, /* A4 Tech 4D Mouse */
+ 0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse, },
+ { MOUSE_MODEL_4DPLUS, /* A4 Tech 4D+ Mouse */
+ 0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus, },
+ { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
+ 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli, },
+ { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */
+ 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, },
{ MOUSE_MODEL_THINK, /* Kensignton ThinkingMouse */
0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, },
- { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */
- 0xc8, MOUSE_INTELLI_PACKETSIZE, enable_msintelli, },
{ MOUSE_MODEL_VERSAPAD, /* Interlink electronics VersaPad */
0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, },
{ MOUSE_MODEL_GENERIC,
@@ -295,6 +301,7 @@ static device_method_t psm_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, psmprobe),
DEVMETHOD(device_attach, psmattach),
+ DEVMETHOD(device_detach, psmdetach),
DEVMETHOD(device_resume, psmresume),
{ 0, 0 }
@@ -306,6 +313,14 @@ static driver_t psm_driver = {
sizeof(struct psm_softc),
};
+#if notyet
+static struct isa_pnp_id psm_ids[] = {
+ { 0x130fd041, "PS/2 mouse port" }, /* PNP0F13 */
+ { 0x1303d041, "PS/2 port" }, /* PNP0313, XXX */
+ { 0 }
+};
+#endif
+
#define CDEV_MAJOR 21
static struct cdevsw psm_cdevsw = {
@@ -461,7 +476,6 @@ set_mouse_resolution(KBDC kbdc, int val)
return ((res == PSM_ACK) ? val : -1);
}
-#ifdef PSM_RESETAFTERSUSPEND
/*
* NOTE: once `set_mouse_mode()' is called, the mouse device must be
* re-enabled by calling `enable_aux_dev()'
@@ -477,8 +491,6 @@ set_mouse_mode(KBDC kbdc)
return (res == PSM_ACK);
}
-#endif /* PSM_RESETAFTERSUSPEND */
-
static int
get_mouse_buttons(KBDC kbdc)
@@ -517,6 +529,7 @@ is_a_mouse(int id)
PSM_MOUSE_ID, /* mouse */
PSM_BALLPOINT_ID, /* ballpoint device */
PSM_INTELLI_ID, /* Intellimouse */
+ PSM_EXPLORER_ID, /* Intellimouse Explorer */
-1 /* end of table */
};
int i;
@@ -537,13 +550,16 @@ model_name(int model)
int model_code;
char *model_name;
} models[] = {
- { MOUSE_MODEL_NETSCROLL, "NetScroll Mouse" },
- { MOUSE_MODEL_NET, "NetMouse" },
+ { MOUSE_MODEL_NETSCROLL, "NetScroll" },
+ { MOUSE_MODEL_NET, "NetMouse/NetScroll Optical" },
{ MOUSE_MODEL_GLIDEPOINT, "GlidePoint" },
{ MOUSE_MODEL_THINK, "ThinkingMouse" },
{ MOUSE_MODEL_INTELLI, "IntelliMouse" },
{ MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" },
{ MOUSE_MODEL_VERSAPAD, "VersaPad" },
+ { MOUSE_MODEL_EXPLORER, "IntelliMouse Explorer" },
+ { MOUSE_MODEL_4D, "4D Mouse" },
+ { MOUSE_MODEL_4DPLUS, "4D+ Mouse" },
{ MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" },
{ MOUSE_MODEL_UNKNOWN, NULL },
};
@@ -591,13 +607,14 @@ restore_controller(KBDC kbdc, int command_byte)
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;
}
}
-#ifdef PSM_RESETAFTERSUSPEND
/*
* Re-initialize the aux port and device. The aux port must be enabled
* and its interrupt must be disabled before calling this routine.
@@ -704,7 +721,6 @@ reinitialize(int unit, mousemode_t *mode)
return TRUE;
}
-#endif /* PSM_RESETAFTERSUSPEND */
static int
doopen(int unit, int command_byte)
@@ -756,6 +772,10 @@ doopen(int unit, int command_byte)
return (EIO);
}
+ /* start the watchdog timer */
+ sc->watchdog = FALSE;
+ sc->callout = timeout(psmtimeout, (void *)unit, hz*2);
+
return (0);
}
@@ -773,22 +793,38 @@ psmprobe(device_t dev)
{
int unit = device_get_unit(dev);
struct psm_softc *sc = device_get_softc(dev);
- uintptr_t port;
+ uintptr_t irq;
uintptr_t flags;
int stat[3];
int command_byte;
int mask;
+ int rid;
int i;
#if 0
kbdc_debug(TRUE);
#endif
- BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_PORT, &port);
+
+#if notyet
+ /* check PnP IDs */
+ if (XXX_PNP_PROBE(device_get_parent(dev), dev, psm_ids) == ENXIO)
+ return ENXIO;
+#endif
+
+ BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
- sc->addr = port;
- sc->kbdc = kbdc_open(sc->addr);
+ sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev)));
sc->config = flags & 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;
@@ -939,6 +975,9 @@ psmprobe(device_t dev)
break;
case PSM_MOUSE_ID:
case PSM_INTELLI_ID:
+ case PSM_EXPLORER_ID:
+ case PSM_4DMOUSE_ID:
+ case PSM_4DPLUS_ID:
sc->hw.type = MOUSE_MOUSE;
break;
default:
@@ -1044,6 +1083,18 @@ psmprobe(device_t dev)
endprobe(ENXIO);
}
+ /* see if IRQ is available */
+ rid = 0;
+ sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
+ RF_ACTIVE);
+ if (sc->intr == NULL) {
+ printf("psm%d: unable to allocate the IRQ resource (%d).\n",
+ unit, irq);
+ endprobe(ENXIO);
+ } else {
+ bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr);
+ }
+
/* done */
kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
kbdc_lock(sc->kbdc, FALSE);
@@ -1055,20 +1106,36 @@ psmattach(device_t dev)
{
int unit = device_get_unit(dev);
struct psm_softc *sc = device_get_softc(dev);
- void *ih;
- struct resource *res;
uintptr_t irq;
- int zero = 0;
+ int error;
+ int rid;
if (sc == NULL) /* shouldn't happen */
return (ENXIO);
/* Setup initial state */
sc->state = PSM_VALID;
+ callout_handle_init(&sc->callout);
+
+ /* Setup our interrupt handler */
+ rid = 0;
+ BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
+ sc->intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
+ RF_ACTIVE);
+ if (sc->intr == NULL)
+ return (ENXIO);
+ error = BUS_SETUP_INTR(device_get_parent(dev), 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 */
- make_dev(&psm_cdevsw, PSM_MKMINOR(unit, FALSE), 0, 0, 0666, "psm%d", unit);
- make_dev(&psm_cdevsw, PSM_MKMINOR(unit, TRUE), 0, 0, 0666, "bpsm%d", unit);
+ 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);
if (!verbose) {
printf("psm%d: model %s, device ID %d\n",
@@ -1086,16 +1153,30 @@ psmattach(device_t dev)
if (bootverbose)
--verbose;
- BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
- res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
- RF_SHAREABLE | RF_ACTIVE);
- BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY,
- psmintr, sc, &ih);
-
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 = 0;
+ BUS_TEARDOWN_INTR(device_get_parent(dev), 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(dev_t dev, int flag, int fmt, struct proc *p)
{
int unit = PSM_UNIT(dev);
@@ -1121,6 +1202,7 @@ psmopen(dev_t dev, int flag, int fmt, struct proc *p)
sc->rsel.si_pid = 0;
sc->mode.level = sc->dflt_mode.level;
sc->mode.protocol = sc->dflt_mode.protocol;
+ sc->watchdog = FALSE;
/* flush the event queue */
sc->queue.count = 0;
@@ -1206,7 +1288,7 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
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",
- PSM_UNIT(dev));
+ 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
@@ -1216,6 +1298,10 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
}
splx(s);
+ /* stop the watchdog timer */
+ untimeout(psmtimeout, (void *)unit, sc->callout);
+ callout_handle_init(&sc->callout);
+
/* remove anything left in the output buffer */
empty_aux_buffer(sc->kbdc, 10);
@@ -1229,12 +1315,12 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
* hereafter.
*/
log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n",
- PSM_UNIT(dev));
+ unit);
}
if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3)
log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n",
- PSM_UNIT(dev));
+ unit);
}
if (!set_controller_command_byte(sc->kbdc,
@@ -1245,7 +1331,7 @@ psmclose(dev_t dev, int flag, int fmt, struct proc *p)
* we shall ignore this error; see the above comment.
*/
log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n",
- PSM_UNIT(dev));
+ unit);
}
/* remove anything left in the output buffer */
@@ -1738,6 +1824,23 @@ psmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
}
static void
+psmtimeout(void *arg)
+{
+ struct psm_softc *sc;
+ int unit;
+
+ unit = (int)arg;
+ sc = devclass_get_softc(psm_devclass, unit);
+ if (sc->watchdog) {
+ if (verbose >= 4)
+ log(LOG_DEBUG, "psm%d: lost interrupt?\n", unit);
+ psmintr(sc);
+ }
+ sc->watchdog = TRUE;
+ sc->callout = timeout(psmtimeout, (void *)unit, hz);
+}
+
+static void
psmintr(void *arg)
{
/*
@@ -1805,11 +1908,9 @@ psmintr(void *arg)
/*
* A kludge for Kensington device!
* The MSB of the horizontal count appears to be stored in
- * a strange place. This kludge doesn't affect other mice
- * because the bit is the overflow bit which is, in most cases,
- * expected to be zero when we reach here. XXX
+ * a strange place.
*/
- if (sc->hw.model != MOUSE_MODEL_VERSAPAD)
+ if (sc->hw.model == MOUSE_MODEL_THINK)
sc->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0;
/* ignore the overflow bits... */
@@ -1824,10 +1925,38 @@ psmintr(void *arg)
switch (sc->hw.model) {
+ case MOUSE_MODEL_EXPLORER:
+ /*
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * byte 1: oy ox sy sx 1 M R L
+ * byte 2: x x x x x x x x
+ * byte 3: y y y y y y y y
+ * byte 4: * * S2 S1 s d2 d1 d0
+ *
+ * L, M, R, S1, S2: left, middle, right and side buttons
+ * s: wheel data sign bit
+ * d2-d0: wheel data
+ */
+ z = (sc->ipacket[3] & MOUSE_EXPLORER_ZNEG)
+ ? (sc->ipacket[3] & 0x0f) - 16 : (sc->ipacket[3] & 0x0f);
+ ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN)
+ ? MOUSE_BUTTON4DOWN : 0;
+ ms.button |= (sc->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN)
+ ? MOUSE_BUTTON5DOWN : 0;
+ break;
+
case MOUSE_MODEL_INTELLI:
case MOUSE_MODEL_NET:
/* wheel data is in the fourth byte */
z = (char)sc->ipacket[3];
+ /* some mice may send 7 when there is no Z movement?! XXX */
+ if ((z >= 7) || (z <= -7))
+ z = 0;
+ /* some compatible mice have additional buttons */
+ ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN)
+ ? MOUSE_BUTTON4DOWN : 0;
+ ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN)
+ ? MOUSE_BUTTON5DOWN : 0;
break;
case MOUSE_MODEL_MOUSEMANPLUS:
@@ -1880,18 +2009,40 @@ psmintr(void *arg)
? MOUSE_BUTTON5DOWN : 0;
break;
case 2:
- /* this packet type is reserved, and currently ignored */
- /* FALL THROUGH */
+ /* this packet type is reserved by Logitech... */
+ /*
+ * IBM ScrollPoint Mouse uses this packet type to
+ * encode both vertical and horizontal scroll movement.
+ */
+ x = y = 0;
+ /* horizontal count */
+ if (sc->ipacket[2] & 0x0f)
+ z = (sc->ipacket[2] & MOUSE_SPOINT_WNEG) ? -2 : 2;
+ /* vertical count */
+ if (sc->ipacket[2] & 0xf0)
+ z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1;
+#if 0
+ /* vertical count */
+ z = (sc->ipacket[2] & MOUSE_SPOINT_ZNEG)
+ ? ((sc->ipacket[2] >> 4) & 0x0f) - 16
+ : ((sc->ipacket[2] >> 4) & 0x0f);
+ /* horizontal count */
+ w = (sc->ipacket[2] & MOUSE_SPOINT_WNEG)
+ ? (sc->ipacket[2] & 0x0f) - 16
+ : (sc->ipacket[2] & 0x0f);
+#endif
+ break;
case 0:
/* device type packet - shouldn't happen */
/* FALL THROUGH */
default:
x = y = 0;
ms.button = ms.obutton;
- log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
- "0x%02x 0x%02x 0x%02x\n",
- MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
- sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
+ if (bootverbose)
+ log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: "
+ "0x%02x 0x%02x 0x%02x\n",
+ MOUSE_PS2PLUS_PACKET_TYPE(sc->ipacket),
+ sc->ipacket[0], sc->ipacket[1], sc->ipacket[2]);
break;
}
} else {
@@ -1906,9 +2057,11 @@ psmintr(void *arg)
break;
case MOUSE_MODEL_NETSCROLL:
- /* three addtional bytes encode button and wheel events */
- ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN)
+ /* three addtional bytes encode buttons and wheel events */
+ ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON3DOWN)
? MOUSE_BUTTON4DOWN : 0;
+ ms.button |= (sc->ipacket[3] & MOUSE_PS2_BUTTON1DOWN)
+ ? MOUSE_BUTTON5DOWN : 0;
z = (sc->ipacket[3] & MOUSE_PS2_XNEG)
? sc->ipacket[4] - 256 : sc->ipacket[4];
break;
@@ -1973,6 +2126,60 @@ psmintr(void *arg)
| ((y < 0) ? MOUSE_PS2_YNEG : 0);
break;
+ case MOUSE_MODEL_4D:
+ /*
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * byte 1: s2 d2 s1 d1 1 M R L
+ * byte 2: sx x x x x x x x
+ * byte 3: sy y y y y y y y
+ *
+ * s1: wheel 1 direction
+ * d1: wheel 1 data
+ * s2: wheel 2 direction
+ * d2: wheel 2 data
+ */
+ x = (sc->ipacket[1] & 0x80) ? sc->ipacket[1] - 256 : sc->ipacket[1];
+ y = (sc->ipacket[2] & 0x80) ? sc->ipacket[2] - 256 : sc->ipacket[2];
+ switch (c & MOUSE_4D_WHEELBITS) {
+ case 0x10:
+ z = 1;
+ break;
+ case 0x30:
+ z = -1;
+ break;
+ case 0x40: /* 2nd wheel turning right XXX */
+ z = 2;
+ break;
+ case 0xc0: /* 2nd wheel turning left XXX */
+ z = -2;
+ break;
+ }
+ break;
+
+ case MOUSE_MODEL_4DPLUS:
+ if ((x < 16 - 256) && (y < 16 - 256)) {
+ /*
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * byte 1: 0 0 1 1 1 M R L
+ * byte 2: 0 0 0 0 1 0 0 0
+ * byte 3: 0 0 0 0 S s d1 d0
+ *
+ * L, M, R, S: left, middle, right and side buttons
+ * s: wheel data sign bit
+ * d1-d0: wheel data
+ */
+ x = y = 0;
+ if (sc->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN)
+ ms.button |= MOUSE_BUTTON4DOWN;
+ z = (sc->ipacket[2] & MOUSE_4DPLUS_ZNEG)
+ ? ((sc->ipacket[2] & 0x07) - 8)
+ : (sc->ipacket[2] & 0x07) ;
+ } else {
+ /* preserve previous button states */
+ ms.button |= ms.obutton & MOUSE_EXTBUTTONS;
+ }
+ break;
+
case MOUSE_MODEL_GENERIC:
default:
break;
@@ -2012,6 +2219,8 @@ psmintr(void *arg)
sc->status.button = ms.button;
sc->button = ms.button;
+ sc->watchdog = FALSE;
+
/* queue data */
if (sc->queue.count + sc->inputbytes < sizeof(sc->queue.buf)) {
l = min(sc->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail);
@@ -2089,7 +2298,7 @@ enable_lcordless(struct psm_softc *sc)
}
#endif /* notyet */
-/* Genius NetScroll Mouse */
+/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */
static int
enable_groller(struct psm_softc *sc)
{
@@ -2120,13 +2329,12 @@ enable_groller(struct psm_softc *sc)
return FALSE;
if ((status[1] != '3') || (status[2] != 'D'))
return FALSE;
- /* FIXME!! */
- sc->hw.buttons = get_mouse_buttons(sc->kbdc);
+ /* FIXME: SmartScroll Mouse has 5 buttons! XXX */
sc->hw.buttons = 4;
return TRUE;
}
-/* Genius NetMouse/NetMouse Pro */
+/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */
static int
enable_gmouse(struct psm_softc *sc)
{
@@ -2226,7 +2434,7 @@ enable_kmouse(struct psm_softc *sc)
return TRUE;
}
-/* Logitech MouseMan+/FirstMouse+ */
+/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */
static int
enable_mmanplus(struct psm_softc *sc)
{
@@ -2240,6 +2448,11 @@ enable_mmanplus(struct psm_softc *sc)
int i;
/* the special sequence to enable the fourth button and the roller. */
+ /*
+ * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION
+ * must be called exactly three times since the last RESET command
+ * before this sequence. XXX
+ */
for (i = 0; i < sizeof(res)/sizeof(res[0]); ++i) {
if (res[i] < 0) {
if (!set_mouse_scaling(kbdc, 1))
@@ -2262,7 +2475,7 @@ enable_mmanplus(struct psm_softc *sc)
* byte 3: m7 m6 m5 m4 m3 m2 m1 m0
*
* p3-p0: packet type: 0
- * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51,...
+ * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51, ScrollPoint:0x58...
*/
/* check constant bits */
if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC)
@@ -2288,6 +2501,31 @@ enable_mmanplus(struct psm_softc *sc)
return TRUE;
}
+/* MS IntelliMouse Explorer */
+static int
+enable_msexplorer(struct psm_softc *sc)
+{
+ static unsigned char rate[] = { 200, 200, 80, };
+ KBDC kbdc = sc->kbdc;
+ int id;
+ int i;
+
+ /* the special sequence to enable the extra buttons and the roller. */
+ for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
+ if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+ return FALSE;
+ }
+ /* the device will give the genuine ID only after the above sequence */
+ id = get_aux_id(kbdc);
+ if (id != PSM_EXPLORER_ID)
+ return FALSE;
+
+ sc->hw.hwid = id;
+ sc->hw.buttons = 5; /* IntelliMouse Explorer XXX */
+
+ return TRUE;
+}
+
/* MS IntelliMouse */
static int
enable_msintelli(struct psm_softc *sc)
@@ -2318,6 +2556,70 @@ enable_msintelli(struct psm_softc *sc)
return TRUE;
}
+/* A4 Tech 4D Mouse */
+static int
+enable_4dmouse(struct psm_softc *sc)
+{
+ /*
+ * Newer wheel mice from A4 Tech may use the 4D+ protocol.
+ */
+
+ static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
+ KBDC kbdc = sc->kbdc;
+ int id;
+ int i;
+
+ for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
+ if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+ return FALSE;
+ }
+ id = get_aux_id(kbdc);
+ /*
+ * WinEasy 4D: 6
+ * Cable-Free 4D: 8 (4DPLUS)
+ * 4 Way ScrollMouse 4D+: 8 (4DPLUS)
+ */
+ if (id != PSM_4DMOUSE_ID)
+ return FALSE;
+
+ sc->hw.hwid = id;
+ sc->hw.buttons = 3; /* XXX some 4D mice have 4? */
+
+ return TRUE;
+}
+
+/* A4 Tech 4D+ Mouse */
+static int
+enable_4dplus(struct psm_softc *sc)
+{
+ /*
+ * Newer wheel mice from A4 Tech seem to use this protocol.
+ * Older models are recognized as either 4D Mouse or IntelliMouse.
+ */
+ KBDC kbdc = sc->kbdc;
+ int id;
+
+ /*
+ * enable_4dmouse() already issued the following ID sequence...
+ static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 };
+ int i;
+
+ for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) {
+ if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i])
+ return FALSE;
+ }
+ */
+
+ id = get_aux_id(kbdc);
+ if (id != PSM_4DPLUS_ID)
+ return FALSE;
+
+ sc->hw.hwid = id;
+ sc->hw.buttons = 4; /* XXX */
+
+ return TRUE;
+}
+
/* Interlink electronics VersaPad */
static int
enable_versapad(struct psm_softc *sc)
@@ -2337,13 +2639,14 @@ enable_versapad(struct psm_softc *sc)
return FALSE;
set_mouse_scaling(kbdc, 1); /* set scale 1:1 */
+ sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND;
+
return TRUE; /* PS/2 absolute mode */
}
static int
psmresume(device_t dev)
{
-#ifdef PSM_HOOKRESUME
struct psm_softc *sc = device_get_softc(dev);
int unit = device_get_unit(dev);
int err = 0;
@@ -2353,11 +2656,19 @@ psmresume(device_t dev)
if (verbose >= 2)
log(LOG_NOTICE, "psm%d: system resume hook called.\n", unit);
+ if (!(sc->config & PSM_CONFIG_HOOKRESUME))
+ return (0);
+
/* 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 *)unit, 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);
@@ -2385,20 +2696,20 @@ psmresume(device_t dev)
}
sc->inputbytes = 0;
-#ifdef PSM_RESETAFTERSUSPEND
/* try to detect the aux device; are you still there? */
- if (reinitialize(unit, &sc->mode)) {
- /* 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! (psmresume).\n",
- unit);
- err = ENXIO;
+ if (sc->config & PSM_CONFIG_INITAFTERSUSPEND) {
+ if (reinitialize(unit, &sc->mode)) {
+ /* 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! (psmresume).\n",
+ unit);
+ err = ENXIO;
+ }
}
-#endif /* PSM_RESETAFTERSUSPEND */
splx(s);
/* restore the driver state */
@@ -2436,9 +2747,6 @@ psmresume(device_t dev)
log(LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit);
return (err);
-#else /* !PSM_HOOKRESUME */
- return (0);
-#endif /* PSM_HOOKRESUME */
}
DRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0);
diff --git a/sys/sys/mouse.h b/sys/sys/mouse.h
index 12d49a2..670f2ae 100644
--- a/sys/sys/mouse.h
+++ b/sys/sys/mouse.h
@@ -116,6 +116,9 @@ typedef struct mousehw {
#define MOUSE_MODEL_MOUSEMANPLUS 7
#define MOUSE_MODEL_KIDSPAD 8
#define MOUSE_MODEL_VERSAPAD 9
+#define MOUSE_MODEL_EXPLORER 10
+#define MOUSE_MODEL_4D 11
+#define MOUSE_MODEL_4DPLUS 12
typedef struct mousemode {
int protocol; /* MOUSE_PROTO_XXX */
@@ -128,6 +131,16 @@ typedef struct mousemode {
} mousemode_t;
/* protocol */
+/*
+ * Serial protocols:
+ * Microsoft, MouseSystems, Logitech, MM series, MouseMan, Hitachi Tablet,
+ * GlidePoint, IntelliMouse, Thinking Mouse, MouseRemote, Kidspad,
+ * VersaPad
+ * Bus mouse protocols:
+ * bus, InPort
+ * PS/2 mouse protocol:
+ * PS/2
+ */
#define MOUSE_PROTO_UNKNOWN (-1)
#define MOUSE_PROTO_MS 0 /* Microsoft Serial, 3 bytes */
#define MOUSE_PROTO_MSC 1 /* Mouse Systems, 5 bytes */
@@ -193,7 +206,7 @@ typedef struct mousevar {
/* MS IntelliMouse (variant of MS Serial) */
#define MOUSE_INTELLI_PACKETSIZE 4
-#define MOUSE_INTELLI_BUTTON2DOWN 0x10 /* middle button the 4th byte */
+#define MOUSE_INTELLI_BUTTON2DOWN 0x10 /* middle button in the 4th byte */
/* Mouse Systems Corp. mouse data packet */
#define MOUSE_MSC_PACKETSIZE 5
@@ -228,16 +241,34 @@ typedef struct mousevar {
* Yes! this is the same bit
* as SYNC!
*/
-#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10 /* 4th button on MouseMan+ */
-#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
#define MOUSE_PS2_XNEG 0x10
#define MOUSE_PS2_YNEG 0x20
#define MOUSE_PS2_XOVERFLOW 0x40
#define MOUSE_PS2_YOVERFLOW 0x80
-#define MOUSE_PS2PLUS_ZNEG 0x08 /* MouseMan+ negative wheel movement */
+
+/* Logitech MouseMan+ (PS/2) data packet (PS/2++ protocol) */
#define MOUSE_PS2PLUS_SYNCMASK 0x48
#define MOUSE_PS2PLUS_SYNC 0x48
+#define MOUSE_PS2PLUS_ZNEG 0x08 /* sign bit */
+#define MOUSE_PS2PLUS_BUTTON4DOWN 0x10 /* 4th button on MouseMan+ */
+#define MOUSE_PS2PLUS_BUTTON5DOWN 0x20
+
+/* IBM ScrollPoint (PS/2) also uses PS/2++ protocol */
+#define MOUSE_SPOINT_ZNEG 0x80 /* sign bits */
+#define MOUSE_SPOINT_WNEG 0x08
+
+/* MS IntelliMouse (PS/2) data packet */
+#define MOUSE_PS2INTELLI_PACKETSIZE 4
+/* some compatible mice have additional buttons */
+#define MOUSE_PS2INTELLI_BUTTON4DOWN 0x40
+#define MOUSE_PS2INTELLI_BUTTON5DOWN 0x80
+
+/* MS IntelliMouse Explorer (PS/2) data packet (variation of IntelliMouse) */
+#define MOUSE_EXPLORER_ZNEG 0x08 /* sign bit */
+/* IntelliMouse Explorer has additional button data in the fourth byte */
+#define MOUSE_EXPLORER_BUTTON4DOWN 0x10
+#define MOUSE_EXPLORER_BUTTON5DOWN 0x20
/* Interlink VersaPad (serial I/F) data packet */
#define MOUSE_VERSA_PACKETSIZE 6
@@ -261,6 +292,15 @@ typedef struct mousevar {
#define MOUSE_PS2VERSA_BUTTON3DOWN 0x01 /* right */
#define MOUSE_PS2VERSA_TAP 0x02
+/* A4 Tech 4D Mouse (PS/2) data packet */
+#define MOUSE_4D_PACKETSIZE 3
+#define MOUSE_4D_WHEELBITS 0xf0
+
+/* A4 Tech 4D+ Mouse (PS/2) data packet */
+#define MOUSE_4DPLUS_PACKETSIZE 3
+#define MOUSE_4DPLUS_ZNEG 0x04 /* sign bit */
+#define MOUSE_4DPLUS_BUTTON4DOWN 0x08
+
/* sysmouse extended data packet */
/*
* /dev/sysmouse sends data in two formats, depending on the protocol
OpenPOWER on IntegriCloud