Page 1 of 1

PS/2 Mouse Packet Alignment

Posted: Mon Jul 08, 2013 11:43 am
by Geometrian
Hi,

I have written a PS/2 mouse driver, essentially this code translated to C++. The mouse is set up on IRQ 12 and streams packets. It works for a little bit, and then the cursor starts jumping to the edges of the screen.

My assumption is that this is a packet alignment issue.

It is my understanding that interrupts are not disabled by IRQ 12. This means that while the interrupt handler is processing, another byte from the mouse may come in and interrupt it, causing another interrupt handler, and so on. The accumulated information of the interrupt handlers within interrupt handlers would pile up on the stack. In the meantime, the mouse goes nuts (because the input IO and the counter are not atomic).

I could try using "sti" and "cli" as soon as the interrupt handler begins. It seems like that should help a lot, but it's still a race condition before "cli". What other solutions are there?

Thanks,

Re: PS/2 Mouse Packet Alignment

Posted: Mon Jul 08, 2013 11:52 am
by Combuster
It is my understanding that interrupts are not disabled by IRQ 12.
Then you should fix your IDT.
This means that while the interrupt handler is processing, another byte from the mouse may come in and interrupt it
The same interrupt can only be fired again if you have sent an EOI.

In other words, fix your own code first.

Re: PS/2 Mouse Packet Alignment

Posted: Mon Jul 08, 2013 6:42 pm
by Geometrian
Combuster wrote:
It is my understanding that interrupts are not disabled by IRQ 12.
Then you should fix your IDT.
. . . Or my understanding was wrong. I'm pretty certain that my IDT maps IRQs to ISRs well.

What else could be causing a desynchronization?

Re: PS/2 Mouse Packet Alignment

Posted: Mon Jul 08, 2013 11:12 pm
by Combuster
You sound like you didn't bother to check. :roll:

Hint: how many different types of IDT entries exist? what are the differences?

Re: PS/2 Mouse Packet Alignment

Posted: Mon Jul 08, 2013 11:38 pm
by Geometrian
Combuster wrote:Hint: how many different types of IDT entries exist? what are the differences?
Three: interrupt gates, task gates, and trap gates.

I don't know what the task gates are very well, though they're related to task switching. The difference between interrupt gates and trap gates is that interrupt gates do disable interrupts.

Therefore, to keep things simple, my IDT was loaded with 256, 32-bit, interrupt gates.
It is my understanding that interrupts are not disabled by IRQ 12.
So this is bogus. I wrote the IDT code a while ago, so I didn't remember the intricacies, but I did pay attention when I wrote it.

Still, now I don't have a hypothesis as to what's happening . . .

Re: PS/2 Mouse Packet Alignment

Posted: Tue Jul 09, 2013 12:38 am
by Geometrian
Checking with the debugger, I was able to see that the IF of EFLAGS is properly cleared (automatically) and restored (with iret) by the ISR for interrupt 44 (mapped by IRQ 12), at least for the first time it happens.

Re: PS/2 Mouse Packet Alignment

Posted: Tue Jul 09, 2013 1:38 am
by Brendan
Hi,
Geometrian wrote:Still, now I don't have a hypothesis as to what's happening . . .
There's at least 2 problems here:
  • the mouse gets out of sync
  • the mouse driver fails to detect or handle "out of sync"
I'd fix the second problem first. For all of the different "PS/2 mouse" protocols, there are ways to detect when synchronisation has been lost. For example, for the "generic 3-button mouse" protocol you'll see that bit 3 of the first byte is always supposed to be set. You should change your code to test this. For example, you could do:

Code: Select all

    case 0:
          mouse_byte[0]=inportb(0x60);
          if( (mouse_byte[0] & 0x08) != 0) {
              mouse_cycle++;                // Only accept this as the first byte if the "must be 1" bit is set
          }
          break;
That way you might accept a few "out of sync" packets, but you'll get back in sync relatively quickly. Alternatively, if you do detect that the "must be set" bit is not set then you could reset the mouse, do the self-tests, etc again and re-initialise.

For the first problem (why it gets out of sync in the first place); I don't know specifically what the problem might be. However:
  • There's no "separation of concerns". Instead of having one driver for the PS/2 controller and separate drivers for mouse, keyboard, bar-code scanner, etc; you have an "all in one hackfest".
  • Initialisation (for both the PS/2 controller and for the mouse) is considerably inadequate - no self tests, no "get device ID", no "reset", etc (you don't even know if the second PS/2 port exists or works or if a mouse is actually plugged into it).
  • I have no idea what you're doing with the keyboard; and because it's an "all in one hackfest" with inadequate initialisation, I can't rule out the possibility of your mouse code being effected by interactions with the keyboard.
  • Because the PS/2 controller driver doesn't exist; it doesn't handle things like "BAT response" (e.g. if the mouse is unplugged then plugged back in) and "resend". This means that your mouse driver has to do these things, but it doesn't.
  • You don't disable data reporting when you send commands to the mouse. This means that if timing is unlucky you might send a command to the mouse and read the first byte of a movement packet instead of reading the "ACK".
  • You ignore all possible errors; including failing to check if any "ACK" is actually an "ACK", and ignoring any time-out that occurs.
  • You've assumed the "set defaults" command resets the device. It doesn't (that's what the "reset" command is for). This may mean that if any extensions are enabled before your driver starts, you may end up setting the defaults for the previously enabled extension and not disabling the extension. Because you never bother with "get device ID" (and therefore don't know what protocol the mouse is using), this would go undetected and you may end up (e.g.) receiving three 4-byte packets and thinking you've received four 3-byte packets (where one looks right and the next 3 look dodgy).
  • Because the overall quality of the code is lacking; I'd be very tempted to assume that you've taken a "quick and dirty; let's fail to do anything right and ignore USB" approach, and that the mouse may be a USB mouse and that the firmware's "PS/2 emulation" is a pile of broken puke and causing problems

Cheers,

Brendan

Re: PS/2 Mouse Packet Alignment

Posted: Wed Jul 10, 2013 12:32 am
by Geometrian
Brendan wrote:There's at least 2 problems here:
  • the mouse gets out of sync
  • the mouse driver fails to detect or handle "out of sync"
I'd fix the second problem first. . . .
Just as a quick test, I tried the modification you suggested and it didn't magic the problem away.
However:
  • <list of possible reasons, presumably drawing from the information that my code was based on the original linked>
Thanks. The driver was based off of the original link, which didn't match very well with the recommendations on the Wiki. I reread through the PS/2 page, the PS/2 Controller page, the Mouse Input page, and the PS/2 Mouse page. From these, I rewrote from scratch the driver for the PS/2 controller, which for now is only linked with the mouse (no keyboard). For initialization, it follows all but the first two steps of the PS/2 Controller page's recommendation. I don't know what to do about USB initialization (though you did mention that as a possible problem?), and for now I'm assuming that the PS/2 controller actually does exist, as I'm not writing for ancient hardware.

The driver for the PS/2 controller works perfectly, as nearly as I can tell, without any devices. That is, it can set itself up, run self-tests, check both ports, and so on.

However, when adding a mouse, the mouse fails on resetting (which for my driver comprises sending 0xFF and then 0xF6 to restore defaults). I get the proper response of 0xAA after sending 0xFF, but it fails on sending 0xF6, since it returns a response of 0x00 exstead of the expected 0xFA (ACK). I checked the code repeatedly, but found no sign of error. In particular, all commands sent to the device on IO port 0x60 are prefixed with a 0xD4 command to the controller on IO port 0x64, as I understand they should, and all IO whatsoever is guarded by appropriate checks on the input and output flags of the controller's status byte.

I tried figuring out the problem, but I couldn't find reference to any PS/2 command ever returning zero in this way on the Wiki. I wasn't able to perturb the problem out of existence. When initializing the PS/2 controller, I also tried moving the enabling of interrupts from step 9 to a new step 11, which seemed more logical, especially since one of the pages points out that interrupts ought to be disabled while "reprogramming" a PS/2 device (as one is doing in step 10).

My source for the driver comes in four files, from which I have removed extraneous bits for clarity (e.g. extra #includes, most commented code). I would appreciate if someone could look them over? Pastebin:
controller_ps2.h, controller_ps2.cpp
mouse_ps2.h, mouse_ps2.cpp

The files are well-commented C++, and should be easy reading. I release them into the public domain.

Thanks,

Re: PS/2 Mouse Packet Alignment

Posted: Wed Jul 10, 2013 1:49 am
by Brendan
Hi,
Geometrian wrote:
Brendan wrote:There's at least 2 problems here:
  • the mouse gets out of sync
  • the mouse driver fails to detect or handle "out of sync"
I'd fix the second problem first. . . .
Just as a quick test, I tried the modification you suggested and it didn't magic the problem away.
Hrm - in theory it should've helped (unless the mouse is using a different protocol than what you're expecting or something else is going wrong). There's a 50% chance that the bit 3 is set in the second byte and a 50% chance that bit 3 is set in the third byte, so it wouldn't always immediately become synchronised; but you would expect that the more packets that are sent the higher the probability of it getting back in sync would be.
Geometrian wrote:
However:
  • <list of possible reasons, presumably drawing from the information that my code was based on the original linked>
Thanks. The driver was based off of the original link, which didn't match very well with the recommendations on the Wiki. I reread through the PS/2 page, the PS/2 Controller page, the Mouse Input page, and the PS/2 Mouse page. From these, I rewrote from scratch the driver for the PS/2 controller, which for now is only linked with the mouse (no keyboard). For initialization, it follows all but the first two steps of the PS/2 Controller page's recommendation. I don't know what to do about USB initialization (though you did mention that as a possible problem?), and for now I'm assuming that the PS/2 controller actually does exist, as I'm not writing for ancient hardware.
The PS/2 controller existed from the very beginning and will exist in all old "PC compatible" computers. It's new computers (especially Apple's 80x86 machines) that might not have a PS/2 controller.

The problem with USB is that when there's a USB keyboard, most computers will be setup for "PS/2 emulation". In this case the USB controller generates a special SMI (System Management Interrupt) and any access to the PS/2 controller will also generate an SMI, The SMI triggers the firmware's special/hidden SMM code (System Management Mode code) that emulates the PS/2 controller (by talking to the USB controller, etc). This is intended for backward compatibility (so that old software designed for PS/2 keyboard still works for a USB keyboard). However; this is a complex (error prone) arrangement to begin with and there's a very large number of "corner cases" that the firmware should worry about; and firmware developers don't care much about old software (and it's not meant to be used by new software). The end result is that "PS/2 emulation" is usually good enough to work for extremely simple things (e.g. getting scan-codes) but almost always fails as soon as you attempt anything more complicated (e.g. thorough PS/2 controller initialisation).
Geometrian wrote:The driver for the PS/2 controller works perfectly, as nearly as I can tell, without any devices. That is, it can set itself up, run self-tests, check both ports, and so on.

However, when adding a mouse, the mouse fails on resetting (which for my driver comprises sending 0xFF and then 0xF6 to restore defaults). I get the proper response of 0xAA after sending 0xFF, but it fails on sending 0xF6, since it returns a response of 0x00 exstead of the expected 0xFA (ACK).
When you send "reset" (0xFF) some devices (including "generic mouse") do their BAT and send 0xAA (test passed) and then send their "device ID". For a generic mouse the ID is 0x00 (but for other types of devices it can be multiple bytes and there's no real way to determine how many the device might send).

I suspect that you're expecting an ACK (from your "set defaults" command) and getting the ID byte 0x00 left over from the reset instead of the ACK you expect; and that you'd get the ACK after the 0x00.


Cheers,

Brendan

Re: PS/2 Mouse Packet Alignment

Posted: Wed Jul 10, 2013 2:19 am
by Geometrian
Brendan wrote:Hrm - in theory it should've helped (unless the mouse is using a different protocol than what you're expecting or something else is going wrong). There's a 50% chance that the bit 3 is set in the second byte and a 50% chance that bit 3 is set in the third byte, so it wouldn't always immediately become synchronised; but you would expect that the more packets that are sent the higher the probability of it getting back in sync would be.
As soon as the problem occurred, I wasn't really trying to move the mouse, which should have gotten it back in sync by the next packet. Meh. That code was suboptimal anyway.
Brendan wrote:The PS/2 controller existed from the very beginning and will exist in all old "PC compatible" computers. It's new computers (especially Apple's 80x86 machines) that might not have a PS/2 controller.
Oh, interesting! I suppose that makes more sense--gotta get rid of older cruft eventually.
The problem with USB is that when there's a USB keyboard, most computers will be setup for "PS/2 emulation". In this case the USB controller generates a special SMI (System Management Interrupt) and any access to the PS/2 controller will also generate an SMI, The SMI triggers the firmware's special/hidden SMM code (System Management Mode code) that emulates the PS/2 controller (by talking to the USB controller, etc). This is intended for backward compatibility (so that old software designed for PS/2 keyboard still works for a USB keyboard). However; this is a complex (error prone) arrangement to begin with and there's a very large number of "corner cases" that the firmware should worry about; and firmware developers don't care much about old software (and it's not meant to be used by new software). The end result is that "PS/2 emulation" is usually good enough to work for extremely simple things (e.g. getting scan-codes) but almost always fails as soon as you attempt anything more complicated (e.g. thorough PS/2 controller initialisation).
Noted. Still, I have next to nothing implemented, and I don't feel like I'm really close to getting a USB driver working soon. It would be best right now if I could rely on the emulation.
When you send "reset" (0xFF) some devices (including "generic mouse") do their BAT and send 0xAA (test passed) and then send their "device ID". For a generic mouse the ID is 0x00 (but for other types of devices it can be multiple bytes and there's no real way to determine how many the device might send).

I suspect that you're expecting an ACK (from your "set defaults" command) and getting the ID byte 0x00 left over from the reset instead of the ACK you expect; and that you'd get the ACK after the 0x00.
A quick experiment confirms that an ACK does indeed follow the 0x00. If this is indeed acceptable behavior for a mouse, then the wording on the Mouse page here is unclear:
Wiki wrote:The mouse probably sends ACK (0xFA) plus several more bytes, then resets itself, and always sends 0xAA.
I took this to mean that some sequence of bytes is terminated by 0xAA, not that 0xAA must be contained in those bytes, not necessarily last.

My algorithm was to catch the 0xAA (lines 23-27), but that doesn't work. Since there's no way to know what the last byte is, I guess just wait with a timeout until it's done?

If all that's true, give me an ACK and I'll update the Wiki :-)

Re: PS/2 Mouse Packet Alignment

Posted: Wed Jul 10, 2013 7:58 am
by Brendan
Hi,
Geometrian wrote:My algorithm was to catch the 0xAA (lines 23-27), but that doesn't work. Since there's no way to know what the last byte is, I guess just wait with a timeout until it's done?

If all that's true, give me an ACK and I'll update the Wiki :-)
Let's start with AT keyboards. For these, the host sends "reset" (0xFF) and the device responds with either "resend" (0xFE) and does nothing else; or disables itself and responds with "ACK" (0xFA) and begins waiting for the host to either accept its "ACK" or send another command (which I assume would cause the reset to be cancelled). The host accepts the "ACK" by raising the clock and data lines for a minimum of 500 ms; and the device begins its self tests when it sees this happen. The self tests take between 300 ms and 500 ms (and all keyboard LEDs should be lit for this time). When the device has finished its self tests it sends a "BAT status", which is either "all tests passed" (0xAA) or "some tests failed" (0xFC), but any other undefined values are meant to be treated as "some tests failed" too.

For later "MF2" keyboards (as far as I can tell) it's the same; except that they're meant to send 0xFD instead of 0xFC for "some tests failed". In both of these cases there is no "keyboard ID" afterwards, and you do have to issue a "read ID" (0xF2) command to determine the type of device.

For "generic PS/2 mouse" I'd expect that all of the above should be the same; except that the mouse does send "device ID" (0x00) after sending "all tests passed" (0xAA). Note: I'd expect that if the mouse returns "some tests failed" (0xFC) it won't send its device ID. For all other types of PS/2 mouse (e.g. 3-button with scroll wheel, and 5-button "Intellimouse") the reset puts them into "generic PS/2 mouse emulation mode" (all extension/s disabled) and therefore they should respond the same as "generic PS/2 mouse" would.

For remaining PS/2 device types (bar code scanners, touch-pads, touch-screens, etc) I'm not too sure. However; I'd expect that some devices (e.g. bar code scanner) behave like a keyboard and others (e.g. touch-pad, touch-screen) behave like a mouse. Note: I have looked at a "Synaptics TouchPad Interfacing Guide" which suggests that this device pretends to be a "generic PS/2 mouse" (and does send "device ID" (0x00) after sending "all tests passed" (0xAA) ) until after you enable its "special" extensions.

Now; originally "PC compatible" hardware was bad and had no sane way to identify common devices. It wasn't until later that hardware manufacturers realised how important it is for software to be able to determine the type/s of hardware installed; and there was a major push towards allowing this to happen. This started with EISA and "Plug and Play" (which tried to retro-fit device identification to existing things like ISA, serial port devices and parallel port devices), and has continued since (e.g. with PCI and USB specifications). This means that today, for almost all hardware, you can find out what the hardware is and then start suitable drivers for that hardware (which is obviously a lot better than expecting the user to figure out the mess and use things like "config.sys" to tell software what hardware to expect). The problem is trying to apply this "find out what it is then start a suitable driver" model to ancient hardware that wasn't designed for it; like PS/2 and ISA.

For PS/2 devices; the "least worst" approach may be to do the reset and BAT stuff; then ignore any number of "device ID" bytes the device might send; then send the "read ID" command (as this removes differences between "keyboard like" and "mouse like" during the device identification phase). Once you've got the "device ID" you'd still have to do further qualification to determine (e.g.) if it's a generic mouse, a mouse with scroll wheel, a 5-button with scroll wheel mouse, a touch-pad, a touch-screen, etc (e.g. by attempting to enable special extensions/modes and determining if they exist or not). On one hand you'd want to avoid having this "further qualification" mess cluttering up your nice clean PS/2 controller driver. On the other hand; to fully support a modern "find out what device it is then start suitable driver" model you'd have to have the "further qualification" mess cluttering up your PS/2 controller driver.


Cheers,

Brendan

Re: PS/2 Mouse Packet Alignment

Posted: Wed Jul 10, 2013 12:17 pm
by Geometrian
Brendan wrote:Let's start with AT keyboards. For these, the host sends "reset" (0xFF) and the device responds with either "resend" (0xFE) and does nothing else; or disables itself and responds with "ACK" (0xFA) and begins waiting for the host to either accept its "ACK" or send another command (which I assume would cause the reset to be cancelled). The host accepts the "ACK" by raising the clock and data lines for a minimum of 500 ms; and the device begins its self tests when it sees this happen. The self tests take between 300 ms and 500 ms (and all keyboard LEDs should be lit for this time). When the device has finished its self tests it sends a "BAT status", which is either "all tests passed" (0xAA) or "some tests failed" (0xFC), but any other undefined values are meant to be treated as "some tests failed" too.
Again, a lot of this isn't listed on the Wiki page. In particular, the ACK response is not listed as a possibility. I am under the impression that AT keyboards are obsolete. Is this the reason?
Brendan wrote:For "generic PS/2 mouse" I'd expect that all of the above should be the same; except that the mouse does send "device ID" (0x00) after sending "all tests passed" (0xAA). Note: I'd expect that if the mouse returns "some tests failed" (0xFC) it won't send its device ID. For all other types of PS/2 mouse (e.g. 3-button with scroll wheel, and 5-button "Intellimouse") the reset puts them into "generic PS/2 mouse emulation mode" (all extension/s disabled) and therefore they should respond the same as "generic PS/2 mouse" would.
Geometrian wrote:My[ original] algorithm was to catch the 0xAA (lines 23-27), but that doesn't work. Since there's no way to know what the last byte is, I guess just wait with a timeout until it's done?
So, all PS/2 / PS/2-emulating mice return a single device ID byte after 0xAA (the byte stream concludes with 0xAA <id byte>)? If this is the case, one could simply wait for 0xAA and then get the device id right afterward. You say later "any number of \"device ID\" bytes the device might send"--I'm assuming that applies to devices in general, not mice specifically?

Brendan wrote:For later "MF2" keyboards (as far as I can tell) it's the same; except that they're meant to send 0xFD instead of 0xFC for "some tests failed". In both of these cases there is no "keyboard ID" afterwards, and you do have to issue a "read ID" (0xF2) command to determine the type of device.
Brendan wrote:For PS/2 devices; the "least worst" approach may be to do the reset and BAT stuff; then ignore any number of "device ID" bytes the device might send; then send the "read ID" command (as this removes differences between "keyboard like" and "mouse like" during the device identification phase).
This was exactly my plan. However:
Brendan wrote:Once you've got the "device ID" you'd still have to do further qualification to determine (e.g.) if it's a generic mouse, a mouse with scroll wheel, a 5-button with scroll wheel mouse, a touch-pad, a touch-screen, etc (e.g. by attempting to enable special extensions/modes and determining if they exist or not). On one hand you'd want to avoid having this "further qualification" mess cluttering up your nice clean PS/2 controller driver. On the other hand; to fully support a modern "find out what device it is then start suitable driver" model you'd have to have the "further qualification" mess cluttering up your PS/2 controller driver.
I feel like this isn't a lost cause from a design perspective.

My impression is that the PS/2 controller ("keyboard controller") is intertwined with up to two devices, using two different IO ports for reading and writing from/to all three. It's needlessly complicated, and like much of the x86 architecture it relates to, it hasn't aged well. Control can still be naturally separated, though. I encapsulate the PS/2 controller proper in its own class, and have classes for keyboard and mouse that share a common base class.

I currently have the controller assume that the device on the first port is a keyboard and that the device on the second port is a mouse, but a better approach would be to have the device base class support a static .get_new_device(unsigned short port) method, which resets the device on the given port, gets the device's device id in the manner you describe above, allocates an instance of the proper device subclass based on that id, and finally returns the new device as a base class pointer to the controller.

All this assumes a language like C++, but the same semantic separation could be achieved in any language.

This way, the PS/2 controller doesn't need to care what kind of device it has on either port. Since it has a pointer to a base representation of both devices, it would still be able to interact with them as generic devices, which should be all it needs to ever do (in my kernel, each device handles setting itself up with the kernel's API, so the PS/2 controller doesn't need to bother with routing commands (e.g. ISRs) at all). Additionally, the PS/2 controller doesn't need to figure out which kind of device it has on each port--the device base class does it. It makes sense that code for figuring out what specific type of device to change the generic device into should go in the generic device base class common to all devices.

Re: PS/2 Mouse Packet Alignment

Posted: Thu Jul 11, 2013 1:12 am
by Brendan
Hi,
Geometrian wrote:
Brendan wrote:Let's start with AT keyboards. For these, the host sends "reset" (0xFF) and the device responds with either "resend" (0xFE) and does nothing else; or disables itself and responds with "ACK" (0xFA) and begins waiting for the host to either accept its "ACK" or send another command (which I assume would cause the reset to be cancelled). The host accepts the "ACK" by raising the clock and data lines for a minimum of 500 ms; and the device begins its self tests when it sees this happen. The self tests take between 300 ms and 500 ms (and all keyboard LEDs should be lit for this time). When the device has finished its self tests it sends a "BAT status", which is either "all tests passed" (0xAA) or "some tests failed" (0xFC), but any other undefined values are meant to be treated as "some tests failed" too.
Again, a lot of this isn't listed on the Wiki page. In particular, the ACK response is not listed as a possibility. I am under the impression that AT keyboards are obsolete. Is this the reason?
AT keyboards are obsolete (replaced by MF2 keyboards, then replaced by USB) but it still should be mentioned in the wiki as MF2 behaves the same (and other PS/2 devices are very similar).
Geometrian wrote:
Brendan wrote:For "generic PS/2 mouse" I'd expect that all of the above should be the same; except that the mouse does send "device ID" (0x00) after sending "all tests passed" (0xAA). Note: I'd expect that if the mouse returns "some tests failed" (0xFC) it won't send its device ID. For all other types of PS/2 mouse (e.g. 3-button with scroll wheel, and 5-button "Intellimouse") the reset puts them into "generic PS/2 mouse emulation mode" (all extension/s disabled) and therefore they should respond the same as "generic PS/2 mouse" would.
Geometrian wrote:My[ original] algorithm was to catch the 0xAA (lines 23-27), but that doesn't work. Since there's no way to know what the last byte is, I guess just wait with a timeout until it's done?
So, all PS/2 / PS/2-emulating mice return a single device ID byte after 0xAA (the byte stream concludes with 0xAA <id byte>)? If this is the case, one could simply wait for 0xAA and then get the device id right afterward. You say later "any number of \"device ID\" bytes the device might send"--I'm assuming that applies to devices in general, not mice specifically?
For the "read ID" command, the device ID can be none, one or 2 bytes (just for standard types of keyboard and mouse), and there's no guarantee that less common devices couldn't send 3 or more bytes. If some devices send their device ID after "BAT status", and if some devices have 2 (or possibly more) bytes of device ID; then it'd be logical to assume that some devices may send 2 (or possibly more) bytes of device ID after "BAT status" (or at least it would make sense to write code that can handle it correctly just in case).
Geometrian wrote:
Brendan wrote:For later "MF2" keyboards (as far as I can tell) it's the same; except that they're meant to send 0xFD instead of 0xFC for "some tests failed". In both of these cases there is no "keyboard ID" afterwards, and you do have to issue a "read ID" (0xF2) command to determine the type of device.
Brendan wrote:For PS/2 devices; the "least worst" approach may be to do the reset and BAT stuff; then ignore any number of "device ID" bytes the device might send; then send the "read ID" command (as this removes differences between "keyboard like" and "mouse like" during the device identification phase).
This was exactly my plan. However:
Brendan wrote:Once you've got the "device ID" you'd still have to do further qualification to determine (e.g.) if it's a generic mouse, a mouse with scroll wheel, a 5-button with scroll wheel mouse, a touch-pad, a touch-screen, etc (e.g. by attempting to enable special extensions/modes and determining if they exist or not). On one hand you'd want to avoid having this "further qualification" mess cluttering up your nice clean PS/2 controller driver. On the other hand; to fully support a modern "find out what device it is then start suitable driver" model you'd have to have the "further qualification" mess cluttering up your PS/2 controller driver.
I feel like this isn't a lost cause from a design perspective.
For an example; (as far as I know) all synaptics touch-pads start in "generic mouse mode" and report a device ID of 0x00; but they all support the same additional "get model ID" command (that no mouse supports). With the "further qualification mess" in the PS/2 controller driver, you could try the synaptics "get model ID" command and determine if it's a synaptics touch-pad; list the device as "synaptics touch-pad model 1234-5678" in your device manager (even when there's no driver at all); and then try to start a synaptics touch-pad driver for the specific model of touch-pad (and if there is no driver for the specific model, try to start a generic synaptics touch-pad driver, then fall back to a generic mouse driver). Alternatively; you could have a single driver that handles generic 3-button mouse plus all the other types of PS/2 mouse, plus all types of touch-pad, plus all types of touch-screen; that has the same "further qualification mess" but also has to handle everything from mouse scaling to touch-pad gestures to touch-screen calibration.
Geometrian wrote:My impression is that the PS/2 controller ("keyboard controller") is intertwined with up to two devices, using two different IO ports for reading and writing from/to all three. It's needlessly complicated, and like much of the x86 architecture it relates to, it hasn't aged well.
The PS/2 controller is a piece of hardware that controls one or 2 "PS/2 ports"; in the same way that a USB controller is a piece of hardware that controls one or more "USB ports"; or an RS232 serial port controller is a piece of hardware that controls an RS232 serial port.

A PS/2 device is a device that uses "PS/2 serial communication" that plugs into a PS/2 port; in the same way that a USB device is a device that uses "USB serial communication" that plugs into a USB port; or an RS232 device is a device that uses "RS232 serial communication" that plugs into an RS232 port.

There can be an infinite number of different types of PS/2 device that plug into a PS/2 port. For example; if someone wanted to invent a "weather station" PS/2 device (that reports temperature, wind speed and wind direction), or a "GPS" PS/2 device (that reports longitude and latitude), or any other kind of device that plugs into a PS/2 port; they can. In the same way, there can be an infinite number of different types of USB device that plug into a USB port; and there can be an infinite number of different types of RS232 device that plug into an RS232 port. For example; if someone wanted to invent a "weather station" USB device, a "GPS" USB device, any other type of USB device, a "weather station" RS232 device, a "GPS" RS232 device, or any other type of RS232 device; they can.
Geometrian wrote:Control can still be naturally separated, though. I encapsulate the PS/2 controller proper in its own class, and have classes for keyboard and mouse that share a common base class.
For a basic monolithic kernel (where everything you can imagine is built into a single binary) using classes would be enough. Modern monolithic kernels (and micro-kernels too, in a different way) allow device drivers to be implemented as separate modules, as this increases flexibility/extensibility. For example; you can have generic CD containing a relatively small kernel that dynamically loads the drivers it actually needs during boot (with no RAM wasted for unneeded drivers, even though you can't know what will be needed when the kernel was compiled). For another example; when your OS is booted there might not be a driver for "ACME PS/2 touch screen" and you might end up using a "generic PS/2 mouse driver" instead; but 2 weeks later the user might download and install a suitable driver for "ACME PS/2 touch screen" and tell the OS to unload the "generic PS/2 mouse driver" and start the "ACME PS/2 touch screen driver"; all without rebooting or interrupting service. Using classes isn't enough for this - you'd have to have some well defined interface/s that modules use; and these interfaces should be stable (e.g. so that everything doesn't break each time you release a different version of the kernel) and therefore should be defined in some sort of standard/specification (where the modules and your kernel comply with your specification/s).

Also note that for PS/2 devices it's possible for the user to (e.g.) boot the computer with 2 keyboards plugged in; then unplug both the keyboards and plug in a mouse and a touch-screen; then (later on) unplug them and plug in a "PS/2 weather station" and a "PS/2 GPS". This is less common for PS/2; but it's probably a good idea to get used to the idea of "hot-plug" (and design your kernel to support "hot-plug devices") as it's extremely common for other types of devices (especially USB).


Cheers,

Brendan

Re: PS/2 Mouse Packet Alignment

Posted: Thu Jul 11, 2013 2:18 am
by Brendan
Hi,

Just something I forgot to mention...

For hardware; devices are connected to each other. For example, you might have a PS/2 keyboard connected to a USB to PS/2 adapter, connected to a USB hub, connected to a USB controller, connected to a PCI bus. These connections describe a hierarchical tree; where each device (except the root of the tree, e.g. "Computer") has a parent, and where each device has none or more children. For example, the USB hub's parent is the USB controller, and the USB hub may have 3 children (e.g. the USB to PS/2 adapter, and 2 other USB devices).

For software; device drivers talk to each other and form a hierarchical tree that mirrors the hardware's hierarchical tree; where each device driver (except the root of the tree) has a parent and none or more children. For example, the USB hub's device driver would talk to the USB controller's device driver, and the USB hub's driver may have 3 children (including the device driver for the USB to PS/2 adapter, and 2 other drivers).

Device drivers rely on the API/protocol/interface provided by their parent; and provide a API/protocol/interface to their children. They should not care about any of their parent's details. For example; a PS/2 keyboard driver should use a "PS/2 interface" to talk to it's parent; and should not care if the parent is a USB to PS/2 adapter driver or if the parent is a PS/2 controller driver.

Hardware:

Code: Select all

 Computer
  |__PCI_host_controller
       |__PCI_to_LPC_bridge
       |    |__PS/2 controller
       |        |__PS/2 keyboard
       |        |__PS/2 mouse
       |__PCI_to_PCI_bridge
           |__USB_controller
               |__USB_hub
                   |__USB to PS/2 adapter
                       |__PS/2 keyboard
                       |__PS/2 mouse
Software:

Code: Select all

 Computer
  |__PCI_host_controller driver
       |__PCI_to_LPC_bridge driver
       |    |__PS/2 controller driver
       |        |__PS/2 keyboard driver (same as "PS/2 keyboard driver" below)
       |        |__PS/2 mouse driver (same as "PS/2 mouse driver" below)
       |__PCI_to_PCI_bridge driver
           |__USB_controller driver
               |__USB_hub driver
                   |__USB to PS/2 adapter driver
                       |__PS/2 keyboard driver (same as "PS/2 keyboard driver" above)
                       |__PS/2 mouse driver (same as "PS/2 mouse driver" above)
Cheers,

Brendan