NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
port-mac68k/60692: mac68k: adb_direct polls round-robin, halving the mouse sample rate
>Number: 60692
>Category: port-mac68k
>Synopsis: mac68k: adb_direct polls round-robin, halving the mouse sample rate
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: port-mac68k-maintainer
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Sep 08 10:10:00 +0000 2026
>Originator: Ray Tran
>Release: 11.0
>Organization:
Diamond Creek Digital
>Environment:
adb_guess_next_device() is called after every transaction, so the
poll rate is divided evenly between all attached ADB devices
>Description:
adb_direct.c steps to the next device in the device table after every
completed transaction, whatever happened. With a keyboard and a mouse
attached -- the ordinary case -- the mouse therefore receives every
second poll, and its sample rate is half what the bus could deliver.
That is not how the ADB host is supposed to schedule polls. Apple's
Technical Note HW01 ("ADB - The Untold Story: Space Aliens Ate My
Mouse") describes the intended behaviour:
"When an SRQ is not asserted, the host will continually poll the last
device to send it data, sending it talk register 0 commands
periodically. This is done under the assumption that this is likely
to be the next place the user interacts; if the user types a
character, they are very likely to type another soon. On current
hosts, this can happen up to 150 times a second."
and, for the case where another device wants attention:
"It will then begin polling those addresses which it knows hold
devices. If a device does not have any data, the host will move on
to the next address, asking each device in turn, until SRQ is no
longer asserted, indicating that all pending data has been fetched."
Walking the device list is what SRQ is for, and adb_direct.c already
detects SRQ and does exactly that. The unconditional call in the normal
completion path duplicates it, which makes the SRQ branch redundant and
spreads the poll rate across every device instead of concentrating it on
the one the user is actually using.
The devices cooperate with this scheme by design; the same note says a
device "should only respond with data when sent a talk register 0
command if it has new data ... it should not respond at all, allowing
the bus to time out", so polling an idle device repeatedly costs a bus
timeout and nothing else.
>How-To-Repeat:
On a machine with both an ADB keyboard and an ADB mouse, measure the
interval between mouse position updates while moving the pointer
steadily. Measured on a Macintosh Centris 650 with a
histogram in the display driver, over 1714 samples (NetBSD 10.1 at the
time; the driver is unchanged in 11.0 and -current): the gaps form two
clusters, 2-6 ms (44%) and 20-34 ms (29%), with almost nothing near the
15 ms frame period. That is a per-device sample rate around 40 Hz on a
bus the same note says can poll at up to 150 Hz, against a 66.7 Hz
display -- the pointer is under-sampled, and moving it at any speed
produces visible judder in large steps.
>Fix:
Keep polling the device that last had data, as the note describes, and
leave the walking of the device list to the SRQ path that already exists.
A bound is added that the documented design does not need: after
ADB_MAX_SAME_POLLS consecutive polls of one device the driver moves on
regardless. Apple's scheme relies on SRQ being noticed every time, and
that puts keyboard responsiveness entirely on this driver's SRQ
detection; the limit means a missed SRQ costs a device a bounded delay
rather than starving it. At the rates involved that is well under a
tenth of a second, and it does not affect the common case at all.
Tested on a Macintosh Centris 650 running NetBSD 11.0 with an ADB
keyboard and a 100 dpi ADB mouse; applies to -current (11.99.8) with no
fuzz, and that kernel drives adb0/akbd0/ams0 under qemu -M q800.
Applies with "patch -p1" from the top of usr/src; verified with -F0
(no fuzz) against NetBSD-current 11.99.8 (20260830003849Z) and 11.0.
--- a/sys/arch/mac68k/dev/adb_direct.c
+++ b/sys/arch/mac68k/dev/adb_direct.c
@@ -245,6 +245,22 @@
int adbSendTalk = 0; /* the intr routine is sending the talk, not
* the user (II) */
int adbPolling = 0; /* we are polling for service request */
+
+static int adbSamePolls = 0;
+
+#define ADB_MAX_SAME_POLLS 20
int adbPollCmd = 0; /* the last poll command we sent */
u_char adbInputBuffer[ADB_MAX_MSG_LENGTH]; /* data input buffer */
@@ -844,6 +860,7 @@
printf_intr(" xSRQ! ");
#endif
adb_guess_next_device();
+ adbSamePolls = 0; /* walking the list */
#ifdef ADB_DEBUG
if (adb_debug & 0x80)
printf_intr("try 0x%0x ",
@@ -905,7 +922,36 @@
if (adb_debug & 0x80)
printf_intr("XXending ");
#endif
- adb_guess_next_device();
+ /*
+ * Keep polling the device that last had
+ * something to say, rather than stepping
+ * to the next one every single time.
+ */
+ if (++adbSamePolls >= ADB_MAX_SAME_POLLS) {
+ adb_guess_next_device();
+ adbSamePolls = 0;
+ }
adbOutputBuffer[0] = 1;
adbOutputBuffer[1] = ((adbLastDevice & 0x0f) << 4) | 0x0c;
adbSentChars = 0; /* nothing sent yet */
Home |
Main Index |
Thread Index |
Old Index