diff options
author | gibbs <gibbs@FreeBSD.org> | 2004-08-27 21:25:16 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 2004-08-27 21:25:16 +0000 |
commit | 5bf7ce4ba01ea510307250c7b21cad3070d25386 (patch) | |
tree | 81b8c6e0d550281b18d6d82a0caa15f16a5e0526 /sys | |
parent | bae83b759590a5d9571a431d37dc5514d52d1d4a (diff) | |
download | FreeBSD-src-5bf7ce4ba01ea510307250c7b21cad3070d25386.zip FreeBSD-src-5bf7ce4ba01ea510307250c7b21cad3070d25386.tar.gz |
Improve sync recovery algorithm:
o Remove PSM_SYNCERR_THRESHOLD1. This value specified how many sync
errors were required before the mouse is re-initialised.
Re-initialisation is now done after (packetsize * 2) sync errors as
things aren't likely to improve after that.
o Reset lastinputerror when re-initialisation occurs. We don't want
to continue to drop data after re-initialisation.
o Count the number of failed packets independently of the syncerrors
statistic. syncerrors is useful for recovering sync within a single
packet. pkterrors allows us to detect when the mouse changes its
packet mode due to some external event (e.g. KVM switch).
o Reinitialize the mouse if we see more than psmpkterrthresh errors
during the validation period. The validation period begins as soon
as a sync error is detected and continues until psmerrsecs/msecs
time has elapsed. The defaults for these two values force a reset
if we see two packet errors in a 2 second period. This allows rapid
detection of packet framing errors caused by the mouse changing packet
modes.
o Export psmpkterrthresh as a sysctl
o Export psmloglevel as a sysctl.
o Enable more debugging code to be enabled at runtime via psmloglevel.
o Simplify verbose conditioned loging by using a VLOG macro.
o Add several comments describing the sync recovery algorithm of
this driver.
Large Portions by: Brian Somers <brian@Awfulhak.org>
Inspired and Frustrated by: Belkin KVMs
Reviewed by: njl, philip
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/atkbdc/psm.c | 216 | ||||
-rw-r--r-- | sys/isa/psm.c | 216 |
2 files changed, 238 insertions, 194 deletions
diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index d517965..5c6eb88 100644 --- a/sys/dev/atkbdc/psm.c +++ b/sys/dev/atkbdc/psm.c @@ -92,12 +92,16 @@ __FBSDID("$FreeBSD$"); /* debugging */ #ifndef PSM_DEBUG -#define PSM_DEBUG 0 /* logging: 0: none, 1: brief, 2: verbose */ -#endif - -#ifndef PSM_SYNCERR_THRESHOLD1 -#define PSM_SYNCERR_THRESHOLD1 20 +#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 */ @@ -179,7 +183,8 @@ struct psm_softc { /* Driver status information */ int xold; /* previous absolute X position */ int yold; /* previous absolute Y position */ int zmax; /* maximum pressure value for touchpads */ - int syncerrors; /* XXX: KILL ME! */ + 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 */ @@ -383,8 +388,7 @@ enable_aux_dev(KBDC kbdc) int res; res = send_aux_command(kbdc, PSMC_ENABLE_DEV); - if (verbose >= 2) - log(LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res)); return (res == PSM_ACK); } @@ -395,8 +399,7 @@ disable_aux_dev(KBDC kbdc) int res; res = send_aux_command(kbdc, PSMC_DISABLE_DEV); - if (verbose >= 2) - log(LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res)); return (res == PSM_ACK); } @@ -419,9 +422,8 @@ get_mouse_status(KBDC kbdc, int *status, int flag, int len) } empty_aux_buffer(kbdc, 5); res = send_aux_command(kbdc, cmd); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", - (flag == 1) ? "DATA" : "STATUS", res); + VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", + (flag == 1) ? "DATA" : "STATUS", res)); if (res != PSM_ACK) return 0; @@ -431,10 +433,8 @@ get_mouse_status(KBDC kbdc, int *status, int flag, int len) break; } - if (verbose) { - log(LOG_DEBUG, "psm: %s %02x %02x %02x\n", - (flag == 1) ? "data" : "status", status[0], status[1], status[2]); - } + VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n", + (flag == 1) ? "data" : "status", status[0], status[1], status[2])); return i; } @@ -447,8 +447,7 @@ get_aux_id(KBDC kbdc) empty_aux_buffer(kbdc, 5); res = send_aux_command(kbdc, PSMC_SEND_DEV_ID); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res)); if (res != PSM_ACK) return (-1); @@ -456,8 +455,7 @@ get_aux_id(KBDC kbdc) DELAY(10000); id = read_aux_data(kbdc); - if (verbose >= 2) - log(LOG_DEBUG, "psm: device ID: %04x\n", id); + VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id)); return id; } @@ -468,8 +466,7 @@ set_mouse_sampling_rate(KBDC kbdc, int rate) int res; res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res); + VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res)); return ((res == PSM_ACK) ? rate : -1); } @@ -489,9 +486,8 @@ set_mouse_scaling(KBDC kbdc, int scale) break; } res = send_aux_command(kbdc, scale); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", - (scale == PSMC_SET_SCALING21) ? "21" : "11", res); + VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", + (scale == PSMC_SET_SCALING21) ? "21" : "11", res)); return (res == PSM_ACK); } @@ -503,8 +499,7 @@ set_mouse_resolution(KBDC kbdc, int val) int res; res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res); + VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res)); return ((res == PSM_ACK) ? val : -1); } @@ -519,8 +514,7 @@ set_mouse_mode(KBDC kbdc) int res; res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res)); return (res == PSM_ACK); } @@ -626,10 +620,8 @@ recover_from_error(KBDC kbdc) 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) { - if (verbose) - log(LOG_ERR, "psm: keyboard port failed.\n"); - } + if (test_kbd_port(kbdc) != 0) + VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n")); #endif } @@ -827,9 +819,8 @@ reinitialize(struct psm_softc *sc, int doinit) /* save the current controller command byte */ empty_both_buffers(sc->kbdc, 10); c = get_controller_command_byte(sc->kbdc); - if (verbose >= 2) - log(LOG_DEBUG, "psm%d: current command byte: %04x (reinitialize).\n", - sc->unit, c); + 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, @@ -851,6 +842,8 @@ reinitialize(struct psm_softc *sc, int doinit) } 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; @@ -1174,7 +1167,7 @@ psmprobe(device_t dev) else sc->dflt_mode.syncmask[0] = vendortype[i].syncmask; if (sc->config & PSM_CONFIG_FORCETAP) - sc->mode.syncmask[0] &= ~MOUSE_PS2_TAP; + sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP; sc->dflt_mode.syncmask[1] = 0; /* syncbits */ sc->mode = sc->dflt_mode; sc->mode.packetsize = vendortype[i].packetsize; @@ -1355,6 +1348,7 @@ psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) /* 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)) @@ -1455,8 +1449,7 @@ psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) } if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) - log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", - unit); + log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", unit); } if (!set_controller_command_byte(sc->kbdc, @@ -1752,6 +1745,10 @@ psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td case MOUSE_GETMODE: s = spltty(); *(mousemode_t *)addr = sc->mode; + if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { + ((mousemode_t *)addr)->syncmask[0] = 0; + ((mousemode_t *)addr)->syncmask[1] = 0; + } ((mousemode_t *)addr)->resolution = MOUSE_RES_LOW - sc->mode.resolution; switch (sc->mode.level) { @@ -1999,8 +1996,7 @@ psmtimeout(void *arg) sc = (struct psm_softc *)arg; s = spltty(); if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) { - if (verbose >= 4) - log(LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit); + VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit)); psmintr(sc); kbdc_lock(sc->kbdc, FALSE); } @@ -2025,6 +2021,13 @@ SYSCTL_INT(_debug, OID_AUTO, psmsecs, CTLFLAG_RW, &psmsecs, 0, ""); static int psmusecs = 500000; SYSCTL_INT(_debug, OID_AUTO, psmusecs, CTLFLAG_RW, &psmusecs, 0, ""); +static int psmpkterrthresh = 2; +SYSCTL_INT(_debug, OID_AUTO, psmpkterrthresh, CTLFLAG_RW, + &psmpkterrthresh, 0, ""); + +SYSCTL_INT(_debug, OID_AUTO, psmloglevel, CTLFLAG_RW, &verbose, 0, ""); + + static void psmintr(void *arg) { @@ -2032,7 +2035,6 @@ psmintr(void *arg) struct timeval now; int c; packetbuf_t *pb; - int haderror = 0; /* read until there is nothing to read */ @@ -2045,11 +2047,11 @@ psmintr(void *arg) getmicrouptime(&now); if ((pb->inputbytes > 0) && timevalcmp(&now, &sc->inputtimeout, >)) { -#if DEBUG - log(LOG_DEBUG, "psmintr: delay too long; resetting byte count\n"); -#endif + 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; @@ -2059,67 +2061,90 @@ psmintr(void *arg) if (pb->inputbytes < sc->mode.packetsize) continue; -#if DEBUG - log(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]); -#endif + 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 ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) { - if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { - sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]); - sc->flags &= ~PSM_NEED_SYNCBITS; - goto valid_sync; - } -#if DEBUG - log(LOG_DEBUG, "psmintr: out of sync (%04x != %04x) %d" - " cmds since last error.\n", - c & sc->mode.syncmask[0], sc->mode.syncmask[1], - sc->cmdcount - sc->lasterr); -#endif - haderror = 1; + if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { + sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]); + sc->flags &= ~PSM_NEED_SYNCBITS; + VLOG(2, (LOG_DEBUG, "psmintr: Sync bytes now %04x,%04x\n", + sc->mode.syncmask[0], sc->mode.syncmask[0])); + } else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) { + VLOG(3, (LOG_DEBUG, "psmintr: out of sync (%04x != %04x) %d" + " cmds since last error.\n", + c & sc->mode.syncmask[0], sc->mode.syncmask[1], + 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) { -#if DEBUG - log(LOG_DEBUG, "psmintr: discard a byte (%d).\n", sc->syncerrors); -#endif - --pb->inputbytes; - bcopy(&pb->ipacket[1], &pb->ipacket[0], pb->inputbytes); + if (sc->syncerrors >= sc->mode.packetsize * 2 || + sc->pkterrors >= psmpkterrthresh) { + + /* + * 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) { -#if DEBUG - log(LOG_DEBUG, "psmintr: re-enable the mouse.\n"); -#endif + + /* + * 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 if (sc->syncerrors < PSM_SYNCERR_THRESHOLD1) { -#if DEBUG - log(LOG_DEBUG, "psmintr: discard a byte (%d).\n", sc->syncerrors); -#endif - --pb->inputbytes; + } else { + VLOG(3, (LOG_DEBUG, "psmintr: discard a byte (%d)\n", + sc->syncerrors)); + pb->inputbytes--; bcopy(&pb->ipacket[1], &pb->ipacket[0], pb->inputbytes); - } else if (sc->syncerrors >= PSM_SYNCERR_THRESHOLD1) { -#if DEBUG - log(LOG_DEBUG, "psmintr: reset the mouse.\n"); -#endif - reinitialize(sc, TRUE); } continue; } -valid_sync: - /* if this packet is at all bogus then drop the packet. */ - if (haderror || - !timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs, &now)) { + + /* + * 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; - haderror = 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; @@ -2321,11 +2346,10 @@ psmsoftintr(void *arg) default: x = y = 0; ms.button = ms.obutton; - if (bootverbose) - log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: " - "0x%02x 0x%02x 0x%02x\n", - MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket), - pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]); + VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet type %d:" + " 0x%02x 0x%02x 0x%02x\n", + MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket), + pb->ipacket[0], pb->ipacket[1], pb->ipacket[2])); break; } } else { @@ -3245,8 +3269,7 @@ psmresume(device_t dev) int unit = device_get_unit(dev); int err; - if (verbose >= 2) - log(LOG_NOTICE, "psm%d: system resume hook called.\n", unit); + VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit)); if (!(sc->config & PSM_CONFIG_HOOKRESUME)) return (0); @@ -3262,8 +3285,7 @@ psmresume(device_t dev) wakeup(sc); } - if (verbose >= 2) - log(LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit); + VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit)); return (err); } diff --git a/sys/isa/psm.c b/sys/isa/psm.c index d517965..5c6eb88 100644 --- a/sys/isa/psm.c +++ b/sys/isa/psm.c @@ -92,12 +92,16 @@ __FBSDID("$FreeBSD$"); /* debugging */ #ifndef PSM_DEBUG -#define PSM_DEBUG 0 /* logging: 0: none, 1: brief, 2: verbose */ -#endif - -#ifndef PSM_SYNCERR_THRESHOLD1 -#define PSM_SYNCERR_THRESHOLD1 20 +#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 */ @@ -179,7 +183,8 @@ struct psm_softc { /* Driver status information */ int xold; /* previous absolute X position */ int yold; /* previous absolute Y position */ int zmax; /* maximum pressure value for touchpads */ - int syncerrors; /* XXX: KILL ME! */ + 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 */ @@ -383,8 +388,7 @@ enable_aux_dev(KBDC kbdc) int res; res = send_aux_command(kbdc, PSMC_ENABLE_DEV); - if (verbose >= 2) - log(LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res)); return (res == PSM_ACK); } @@ -395,8 +399,7 @@ disable_aux_dev(KBDC kbdc) int res; res = send_aux_command(kbdc, PSMC_DISABLE_DEV); - if (verbose >= 2) - log(LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res)); return (res == PSM_ACK); } @@ -419,9 +422,8 @@ get_mouse_status(KBDC kbdc, int *status, int flag, int len) } empty_aux_buffer(kbdc, 5); res = send_aux_command(kbdc, cmd); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", - (flag == 1) ? "DATA" : "STATUS", res); + VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", + (flag == 1) ? "DATA" : "STATUS", res)); if (res != PSM_ACK) return 0; @@ -431,10 +433,8 @@ get_mouse_status(KBDC kbdc, int *status, int flag, int len) break; } - if (verbose) { - log(LOG_DEBUG, "psm: %s %02x %02x %02x\n", - (flag == 1) ? "data" : "status", status[0], status[1], status[2]); - } + VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n", + (flag == 1) ? "data" : "status", status[0], status[1], status[2])); return i; } @@ -447,8 +447,7 @@ get_aux_id(KBDC kbdc) empty_aux_buffer(kbdc, 5); res = send_aux_command(kbdc, PSMC_SEND_DEV_ID); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res)); if (res != PSM_ACK) return (-1); @@ -456,8 +455,7 @@ get_aux_id(KBDC kbdc) DELAY(10000); id = read_aux_data(kbdc); - if (verbose >= 2) - log(LOG_DEBUG, "psm: device ID: %04x\n", id); + VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id)); return id; } @@ -468,8 +466,7 @@ set_mouse_sampling_rate(KBDC kbdc, int rate) int res; res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res); + VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res)); return ((res == PSM_ACK) ? rate : -1); } @@ -489,9 +486,8 @@ set_mouse_scaling(KBDC kbdc, int scale) break; } res = send_aux_command(kbdc, scale); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", - (scale == PSMC_SET_SCALING21) ? "21" : "11", res); + VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", + (scale == PSMC_SET_SCALING21) ? "21" : "11", res)); return (res == PSM_ACK); } @@ -503,8 +499,7 @@ set_mouse_resolution(KBDC kbdc, int val) int res; res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res); + VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res)); return ((res == PSM_ACK) ? val : -1); } @@ -519,8 +514,7 @@ set_mouse_mode(KBDC kbdc) int res; res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE); - if (verbose >= 2) - log(LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res); + VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res)); return (res == PSM_ACK); } @@ -626,10 +620,8 @@ recover_from_error(KBDC kbdc) 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) { - if (verbose) - log(LOG_ERR, "psm: keyboard port failed.\n"); - } + if (test_kbd_port(kbdc) != 0) + VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n")); #endif } @@ -827,9 +819,8 @@ reinitialize(struct psm_softc *sc, int doinit) /* save the current controller command byte */ empty_both_buffers(sc->kbdc, 10); c = get_controller_command_byte(sc->kbdc); - if (verbose >= 2) - log(LOG_DEBUG, "psm%d: current command byte: %04x (reinitialize).\n", - sc->unit, c); + 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, @@ -851,6 +842,8 @@ reinitialize(struct psm_softc *sc, int doinit) } 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; @@ -1174,7 +1167,7 @@ psmprobe(device_t dev) else sc->dflt_mode.syncmask[0] = vendortype[i].syncmask; if (sc->config & PSM_CONFIG_FORCETAP) - sc->mode.syncmask[0] &= ~MOUSE_PS2_TAP; + sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP; sc->dflt_mode.syncmask[1] = 0; /* syncbits */ sc->mode = sc->dflt_mode; sc->mode.packetsize = vendortype[i].packetsize; @@ -1355,6 +1348,7 @@ psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) /* 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)) @@ -1455,8 +1449,7 @@ psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) } if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) - log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", - unit); + log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", unit); } if (!set_controller_command_byte(sc->kbdc, @@ -1752,6 +1745,10 @@ psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td case MOUSE_GETMODE: s = spltty(); *(mousemode_t *)addr = sc->mode; + if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { + ((mousemode_t *)addr)->syncmask[0] = 0; + ((mousemode_t *)addr)->syncmask[1] = 0; + } ((mousemode_t *)addr)->resolution = MOUSE_RES_LOW - sc->mode.resolution; switch (sc->mode.level) { @@ -1999,8 +1996,7 @@ psmtimeout(void *arg) sc = (struct psm_softc *)arg; s = spltty(); if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) { - if (verbose >= 4) - log(LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit); + VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit)); psmintr(sc); kbdc_lock(sc->kbdc, FALSE); } @@ -2025,6 +2021,13 @@ SYSCTL_INT(_debug, OID_AUTO, psmsecs, CTLFLAG_RW, &psmsecs, 0, ""); static int psmusecs = 500000; SYSCTL_INT(_debug, OID_AUTO, psmusecs, CTLFLAG_RW, &psmusecs, 0, ""); +static int psmpkterrthresh = 2; +SYSCTL_INT(_debug, OID_AUTO, psmpkterrthresh, CTLFLAG_RW, + &psmpkterrthresh, 0, ""); + +SYSCTL_INT(_debug, OID_AUTO, psmloglevel, CTLFLAG_RW, &verbose, 0, ""); + + static void psmintr(void *arg) { @@ -2032,7 +2035,6 @@ psmintr(void *arg) struct timeval now; int c; packetbuf_t *pb; - int haderror = 0; /* read until there is nothing to read */ @@ -2045,11 +2047,11 @@ psmintr(void *arg) getmicrouptime(&now); if ((pb->inputbytes > 0) && timevalcmp(&now, &sc->inputtimeout, >)) { -#if DEBUG - log(LOG_DEBUG, "psmintr: delay too long; resetting byte count\n"); -#endif + 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; @@ -2059,67 +2061,90 @@ psmintr(void *arg) if (pb->inputbytes < sc->mode.packetsize) continue; -#if DEBUG - log(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]); -#endif + 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 ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) { - if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { - sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]); - sc->flags &= ~PSM_NEED_SYNCBITS; - goto valid_sync; - } -#if DEBUG - log(LOG_DEBUG, "psmintr: out of sync (%04x != %04x) %d" - " cmds since last error.\n", - c & sc->mode.syncmask[0], sc->mode.syncmask[1], - sc->cmdcount - sc->lasterr); -#endif - haderror = 1; + if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { + sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]); + sc->flags &= ~PSM_NEED_SYNCBITS; + VLOG(2, (LOG_DEBUG, "psmintr: Sync bytes now %04x,%04x\n", + sc->mode.syncmask[0], sc->mode.syncmask[0])); + } else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) { + VLOG(3, (LOG_DEBUG, "psmintr: out of sync (%04x != %04x) %d" + " cmds since last error.\n", + c & sc->mode.syncmask[0], sc->mode.syncmask[1], + 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) { -#if DEBUG - log(LOG_DEBUG, "psmintr: discard a byte (%d).\n", sc->syncerrors); -#endif - --pb->inputbytes; - bcopy(&pb->ipacket[1], &pb->ipacket[0], pb->inputbytes); + if (sc->syncerrors >= sc->mode.packetsize * 2 || + sc->pkterrors >= psmpkterrthresh) { + + /* + * 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) { -#if DEBUG - log(LOG_DEBUG, "psmintr: re-enable the mouse.\n"); -#endif + + /* + * 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 if (sc->syncerrors < PSM_SYNCERR_THRESHOLD1) { -#if DEBUG - log(LOG_DEBUG, "psmintr: discard a byte (%d).\n", sc->syncerrors); -#endif - --pb->inputbytes; + } else { + VLOG(3, (LOG_DEBUG, "psmintr: discard a byte (%d)\n", + sc->syncerrors)); + pb->inputbytes--; bcopy(&pb->ipacket[1], &pb->ipacket[0], pb->inputbytes); - } else if (sc->syncerrors >= PSM_SYNCERR_THRESHOLD1) { -#if DEBUG - log(LOG_DEBUG, "psmintr: reset the mouse.\n"); -#endif - reinitialize(sc, TRUE); } continue; } -valid_sync: - /* if this packet is at all bogus then drop the packet. */ - if (haderror || - !timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs, &now)) { + + /* + * 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; - haderror = 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; @@ -2321,11 +2346,10 @@ psmsoftintr(void *arg) default: x = y = 0; ms.button = ms.obutton; - if (bootverbose) - log(LOG_DEBUG, "psmintr: unknown PS2++ packet type %d: " - "0x%02x 0x%02x 0x%02x\n", - MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket), - pb->ipacket[0], pb->ipacket[1], pb->ipacket[2]); + VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet type %d:" + " 0x%02x 0x%02x 0x%02x\n", + MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket), + pb->ipacket[0], pb->ipacket[1], pb->ipacket[2])); break; } } else { @@ -3245,8 +3269,7 @@ psmresume(device_t dev) int unit = device_get_unit(dev); int err; - if (verbose >= 2) - log(LOG_NOTICE, "psm%d: system resume hook called.\n", unit); + VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit)); if (!(sc->config & PSM_CONFIG_HOOKRESUME)) return (0); @@ -3262,8 +3285,7 @@ psmresume(device_t dev) wakeup(sc); } - if (verbose >= 2) - log(LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit); + VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit)); return (err); } |