diff options
author | yokota <yokota@FreeBSD.org> | 2000-03-18 15:21:40 +0000 |
---|---|---|
committer | yokota <yokota@FreeBSD.org> | 2000-03-18 15:21:40 +0000 |
commit | b91cbcb4f136bbc6c178bf362bc909c1f1dc8631 (patch) | |
tree | d80e1686adb1efb88325c6782baea25117934aec /sys/dev | |
parent | 1385bc5aceee9e021f47fd7a55cb832c8f106d70 (diff) | |
download | FreeBSD-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).
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/atkbdc/atkbdcreg.h | 3 | ||||
-rw-r--r-- | sys/dev/atkbdc/psm.c | 482 | ||||
-rw-r--r-- | sys/dev/kbd/atkbdcreg.h | 3 |
3 files changed, 401 insertions, 87 deletions
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 |