Re: i8042 access timings

From: Jaco Kroon
Date: Thu Jan 27 2005 - 16:03:24 EST


Linus Torvalds wrote:

On Thu, 27 Jan 2005, Jaco Kroon wrote:

Which indicates (as far as my understanding goes) that the command times out, as such the param value stays the same (ready for re-use in the second command). The second commands succeeds but does not return one of the expected (0x00, 0xff, 0xfa) values, instead it returns the value as expected by the first command (0xa5). The last value on both lines is the return value. From the second snippet:


No, I think the 0x5a you see is the 0x5a that is _still_ there, because we never got any reply at all from the i8042_command(I8042_CMD_AUX_LOOP) case, nor did the I8042_CMD_AUX_TEST thing do anything at all.

I suspect I didn't explain clearly. Note that the outer test expects a 0xa5 (we pass 0x5a in). That is what made me suspect that the second request gets the first ones return value.


I have a suspicion: these commands are also one of the few ones that write a data byte to the data port immediately after writing the command byte to the status port.
Yes. The commands that write something is:

CTL_WCTR
KBD_LOOP (I quess this is what breaks if no USB1.1 present in kernel)
AUX_SEND (obviously)
AUX_LOOP (the one that we think is breaking)
MIX_SEND (obviously).

All of them send exactly one byte.


It so happens that if the hardware is slow to reach to the command byte,
we might read the status word _before_ the hardware has had time to even
say "ok, my input port is now full". We have a "udelay()" there in
i8042_wait_write(), but we have it _after_ we've done the i8042_read_status(), so effectively the i8042_read_status() happens immediately after the i8042_write_command().
Hmm, just an idea, shouldn't the i8042_write_command be waiting until the device has asserted the pin to indicate that the buffer is busy? Ie, some nice and tight loop. This has the downside that if we check _just before_ the pin gets asserted, then delay and check again _after_ it has been cleared we will deadlock. So the udelay() before the loop (or rewriting the loop to do{}while(...)) is probably a better solution, although this will cause us to _always_ wait at least 50 microseconds (not that that is a long time).

So what _might_ happen is that we write the command, and then i8042_wait_write() thinks that there is space to write the data immediately, and writes the data, but now the data got lost because the buffer was busy.
This makes a lot of sense.


The IO delay should be _before_ the read of the status, not after it.

So how about adding an extra "udelay(50)" to either the top of i8042_wait_write(), or to the bottom of "i8042_write_command()"? Does that make any difference?
No. No difference, still the same result.


(50 usec is probably overkill, and an alternative is to just make the
write_data/write_command inline functions in i8042-io.h use the
"inb_p/outb_p" versions that put a serializing IO instruction in between,
which should give you a nice 1us delay even on modern hardware.)
ok, how would I try this? Where can I find an example to code it from? Sorry, I should probably be grepping ...

Jaco
--
There are only 10 kinds of people in this world,
those that understand binary and those that don't.
http://www.kroon.co.za/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/