You need TH and TR set as outputs, with everything else set as inputs. Start with TH and TR set high for a vertical frame period to make sure the mouse is reset to starting a packet read. You then set TH low to start the mouse packet. You then toggle TR and watch TL to see when the mouse is ready. You get a nibble of info on the direction lines with each toggle of TR. You get a header, and then the mouse info. The header is 0x0, 0xB, 0xF, 0xF. The mouse info nibbles are direction-overflow flags, buttons, mouse x high nibble, mouse x low nibble, mouse y high nibble, and mouse y low nibble.
If you're good with C code, here's the code I wrote for sgdk:
static u8 THREELINE_HANDSHAKE(vu8 *pb, u8 ph)
{
u8 val = 0, hs;
*pb = ph; /* next phase in protocol */
/* wait on handshake */
hs = (ph >> 1) & 0x10;
while (retry)
{
val = *pb;
if ((val & 0x10) == hs)
break; /* timeout */
retry--;
}
return val & 0x0F;
}
static s16 start3lhs(u16 port, u8 *hdr, u16 len)
{
vu8 *pb;
u16 I;
retry = 255;
phase = 0x20; /* selected */
/* make sure port direction is correct */
pb = (vu8 *)0xa10009 + port*2;
*pb = 0x60;
/* make sure port is deselected to start at first phase */
pb = (vu8 *)0xa10003 + port*2;
hdr[0] = THREELINE_HANDSHAKE(pb, 0x60);
if (retry)
{
for (I=1; I<len; I++)
{
hdr[I] = THREELINE_HANDSHAKE(pb, phase);
phase ^= 0x20;
if (!retry)
break; /* timeout */
}
}
if (!retry)
*pb = 0x60; /* timeout - end request */
return retry ? 0 : -1;
}
static u16 readMouse(u16 port)
{
vu8 *pb;
u16 val, I, mx, my;
s16 sts;
u8 hdr[4], md[6];
pb = (vu8 *)0xa10003 + port*2;
val = (JOY_TYPE_MOUSE << JOY_TYPE_SHIFT);
sts = start3lhs(port, hdr, 4);
if ((sts == 0) &&
(hdr[0] == 0x00) &&
(hdr[1] == 0x0B) &&
(hdr[2] == 0x0F) &&
(hdr[3] == 0x0F))
{
/* handle mouse */
for (I=0; I<6; I++)
{
md[I] = THREELINE_HANDSHAKE(pb, phase);
phase ^= 0x20;
if (!retry)
break; /* timeout */
}
if (I == 6)
{
if (md[0] & 0x04)
mx = 256; /* x overflow */
else
mx = md[2]<<4 | md[3];
if (md[0] & 0x01)
mx |= 0xFF00; /* x sign extend */
if (md[0] & 0x08)
my = 256; /* y overflow */
else
my = md[4]<<4 | md[5];
if (md[0] & 0x02)
my |= 0xFF00; /* y sign extend */
joyAxisX[port] += (s16)mx;
joyAxisY[port] += (s16)my;
if (md[1] & 8) val |= BUTTON_START;
if (md[1] & 4) val |= BUTTON_MMB;
if (md[1] & 2) val |= BUTTON_RMB;
if (md[1] & 1) val |= BUTTON_LMB;
if ((s16)mx < -2) val |= BUTTON_LEFT;
else if ((s16)mx > 2) val |= BUTTON_RIGHT;
if ((s16)my < -2) val |= BUTTON_DOWN;
else if ((s16)my > 2) val |= BUTTON_UP;
}
}
*pb = 0x60; /* end request */
return val;
}
Most of my examples also have mouse reading code in assembly.