VOGONS


First post, by HwAoRrDk

User metadata
Rank Newbie
Rank
Newbie

I'm attempting to reverse-engineer, using Ghidra, version 6.30 of the Logitech MouseWare driver to find out what potential 'asterisk' commands it's capable of sending to Logitech serial mice. This all started because while some of these commands are documented (e.g. "*n", "*o", etc. for changing baud rates), there are others that still remain a mystery (either in purpose or expected response - e.g. "*#"), so I figured why not try and find out what the mouse driver actually does?

I've thrown the binary (MOUSE.COM, 55KB) into Ghidra and disassembled it as a 16-bit real-mode executable with a memory origin of 0x100. It's identified a whole bunch of functions. And I've managed to go through and identify a large number of strings - mostly messages (inc. the loading message with box-char borders), INI config file keys/values, and command line args. Some oddities: all are null-terminated strings, except the command-line args, which oddly are Pascal strings (i.e. length-prefix), and there are a hell of a lot of empty (i.e. only spaces) strings that seem as if they are 'blanking' strings for overwriting/substituting for other strings. All the null-terminated strings are arranged in 'blocks' followed by a table of pointers to each string in that block; the code only appears to reference the tables, not the strings directly. I even think I've identified the INT33h handler entry point (thanks to this blog post).

In order to try and get to the code that sends commands to the serial mouse, I thought a good place to start would be to identify where it sends data on the serial port, and work backwards. Firstly, it doesn't appear to use INT14h BIOS routines (there are zero instances of an INT 0x14 instruction anywhere, nor a CD 14 byte pair anywhere in the binary), so I assume it must talk to the UART hardware directly. Okay, so it'll be using 3F8/2F8 I/O port base addresses. So I search for all uses of an OUT instruction and come up with only 5 instances in the disassembled code. However, none of them appear to do anything with the UART! 😕

The first is in an apparently general-purpose function that appears to read an arbitrary I/O port register (with IN), bitwise-AND an argument value with the read value, and write it back (with OUT) to the register. The second is in a similar function to the first, but instead bitwise-ORs with the inverted argument value. The third is in a function that appears to read the PIT counter value (via 0x0043). The 4th and 5th are both in the same lengthy function, whose purpose is unclear to me, but appears to do something with reading/writing VGA registers. It sets the target IN/OUT address by reading from a table elsewhere, which appears to be populated with VGA port addresses (0x3C2, 0x3C4, 0x3CE, 0x3D4).

I'm totally mystified that there are no other I/O writes anywhere in the disassembled code! No instruction variants like OUTS, OUTSB, or OUTSW either.

I feel like I may be missing something because there's still a lot of 'junk' data that Ghidra has not disassembled that I suspect may be more code, but there's obviously no point blindly disassembling it without knowing it is: a) actually code, and b) called from somewhere/something (which it apparently isn't). Could there be more interrupt handlers? How do I figure that out?

So I'm kind of stuck. Does anyone have any advice?

Reply 1 of 8, by EduBat

User metadata
Rank Member
Rank
Member

Not sure if it will help or not but, if ctmouse also sends those asterisk commands, it is free software with available sources and it can be studied.

Reply 2 of 8, by jmarsh

User metadata
Rank Oldbie
Rank
Oldbie

Search for the port addresses then find the code that references them.

Reply 3 of 8, by jakethompson1

User metadata
Rank l33t
Rank
l33t

The function at 0x40bd looks promising as highly related to the serial port. In particular the table it references at 0x99a4 has what looks like three function pointers followed by the port numbers 3f8h, 2f8h, 3e8h, and 2e8h. Function 0x43d4 (which 0x40bd calls) looks like the baud rate setting function. It's called with si=0x99f8 and the two bytes there are 0x60 0x00, and after setting port+3 to 0x80 to set the divisor latch access bit, it outputs [si] to port and [si+1] to port+1. 115200/1200=0x60 so that would be defaulting to a baud rate of 1200 which makes sense.

Really it should consult the BIOS data area at 40h:00h and 40h:02h to find the I/O ports of COM1: and COM2:, but I didn't see anything like that. The BIOS cannot tell you the IRQs so perhaps they considered it useless if it's anything other than 3f8/2f8.

Reply 4 of 8, by HwAoRrDk

User metadata
Rank Newbie
Rank
Newbie
EduBat wrote on Yesterday, 21:22:

if ctmouse also sends those asterisk commands

No, it does not.

jmarsh wrote on Yesterday, 21:50:

Search for the port addresses then find the code that references them.

That was one of the first things that came to mind. I could not find any instances of instructions that had the immediate value of 0x3F8 or 0x2F8 (or did something like load a low-byte of 0xF8 and then conditionally a high byte of 0x2/0x3).

Besides, I didn't expect that it would have the serial port addresses hard-coded, because the driver takes which COM port to use from a parameter in the MOUSEDRV.INI configuration file (e.g. "ConnectionPort=COM1"). Which, BTW, is another mystery, because that filename only appears in the binary within message strings, so I have no idea how it actually accesses the file if it doesn't do it by name! 😄

Reply 5 of 8, by HwAoRrDk

User metadata
Rank Newbie
Rank
Newbie
jakethompson1 wrote on Yesterday, 22:30:

The function at 0x40bd looks promising as highly related to the serial port. In particular the table it references at 0x99a4 has what looks like three function pointers followed by the port numbers 3f8h, 2f8h, 3e8h, and 2e8h.

Thank you!! 😃 How did you locate that function? For me that's within a a bunch of the 'junk' data that Ghidra hadn't so far disassembled. Is it referenced from an interrupt handler that I haven't discovered?

It's hard for me to intuit what a section of code does because I'm not at all familiar with x86 assembly, so I would not pick things like this up. Much time is spent referring to x86 instruction and register cheat sheets. 😅

jakethompson1 wrote on Yesterday, 22:30:

Really it should consult the BIOS data area at 40h:00h and 40h:02h to find the I/O ports of COM1: and COM2:, but I didn't see anything like that. The BIOS cannot tell you the IRQs so perhaps they considered it useless if it's anything other than 3f8/2f8.

Yeah, makes sense it doesn't due to what I said in the previous post about it being capable of reading COM port parameters from the INI file (MOUSEDRV.INI can have "[COMx]" sections with "BaseAddress" and "IRQValue" parameters). Although, given that the default MOUSEDRV.INI file doesn't actually include those sections by default, it seems right it would make assumptions about 3F8/2F8 for COM1/COM2.

Reply 6 of 8, by vetz

User metadata
Rank l33t
Rank
l33t

I had Claude check what *# does and according to the findings it's an internal mouse firmware identification protocol. It queries the model number in a 5-byte ASCII string from the mouse to set the correct mouse type and differentiate genuine Logitech mice from generic Microsoft-compatible serial mice on the same port.

3D Accelerated Games List (Proprietary APIs - No 3DFX/Direct3D)
3D Acceleration Comparison Episodes

Reply 7 of 8, by HwAoRrDk

User metadata
Rank Newbie
Rank
Newbie
vetz wrote on Today, 10:35:

I had Claude check what *# does and according to the findings it's an internal mouse firmware identification protocol. It queries the model number in a 5-byte ASCII string from the mouse to set the correct mouse type and differentiate genuine Logitech mice from generic Microsoft-compatible serial mice on the same port.

Yes, I got your private message with the Claude analysis. Very useful! Thanks again. 😁

Reply 8 of 8, by HwAoRrDk

User metadata
Rank Newbie
Rank
Newbie

Thanks to @jakethompson1 and @vetz, I think I now have enough information to satisfactorily answer my own questions about what the asterisk commands used by the driver are. Cross-referencing with existing documentation (LogiMouse C7 Technical Reference Manual, Logitech 3D Mouse & Head Tracker Technical Reference Manual, and Logitech CyberMan 3D SWIFT Supplement) has allowed me to fill in the gaps or guesses/assumptions in their analyses.

Baud-rate commands:

  • *n - 1200 bps (UART divisor of 96)
  • *o - 2400 bps (UART divisor of 48)
  • *p - 4800 bps (UART divisor of 24)
  • *q - 9600 bps (UART divisor of 12)

These are known and all correspond to the documented commands for the C7 mouse.

Protocol-selection commands:

  • *U - Mouse Systems 5-byte protocol, 8N2
  • *T - "Three Byte Packed Binary Format" protocol, 8N2
  • *W - "Hexadecimal Format" 5-byte protocol, 8N2
  • *B - "Relative Bit Pad One Packed Binary" 5-byte protocol, 7E2
  • *S - MM Series 3-byte protocol, 8O2
  • *V - Microsoft 3-byte protocol, 7N1
  • *X - "M+" (i.e. Logitech) 3/4-byte protocol, 7N1

With the exception of 'X', these all correspond to the older non-asterisk commands for the C7 mouse. Also, interesting that it uses 2 stop bits for some protocols, even though those protocols do not require that (for instance, the Mouse Systems documentation explicitly says their protocol is 1 stop bit).

Probe commands:

  • *? - Send standard configuration (4 bytes expected)
  • *! - Send specific configuration (7 bytes expected)
  • *# - Send device identification (5 bytes expected)
  • *c - Send copyright and version number in ASCII (up to 127 bytes expected)

The '?' command will be as documented in the 3D Mouse docs.

The attachment logitech-send-std-cfg-cmd.png is no longer available

The '#' command's expected response format appears to be "M{digit}{cap}{?}{?}", where 'digit' is an ASCII numeric digit in the range 0-7, 'cap' is apparently a low-nibble 4-bit 'capabilities' code, and '?' unknown. I'm thinking the 2nd byte numeric ASCII digit may simply correlate to the "M3" identifier Logitech mice give for RTS toggle, of which the digit is simply a reflection of the number of buttons. That may explain why the code looks for 0-7 - i.e. up to 7 buttons. The capabilities nibble could be something similar to the flags/values described for the '?' command in the 3D Mouse docs; perhaps a device type or protocol supported.

The '!' command, although documented in the 3D Mouse docs, has a response I suspect may be device-specific data that varies by model. The 3D Mouse docs only say that particular device gives a single 5-bit value in the 1st of the 7 bytes, and the rest are unused, so I think it's likely that other models use those other bytes for other data.

The 'c' command corresponds directly to the older non-asterisk command for the C7 mouse. The copyright string should be prepended with CRLF and null-terminated. The 3D Mouse docs give an example of "<CR><LF>JA 1.0 © 1991 Logitech<NUL>" (no idea what "JA" stands for). It seems the exact composition of this message is not important, as the C7 manual says "This function is useful for testing the mouse when it is connected to a simple terminal emulator", and I have seen that the 86Box emulator implements this but sends its own copyright string.