Jump to content

PS2 Protocol in General and Cypress VoodooPS2 kext story


Ulysse31
 Share

7 posts in this topic

Recommended Posts

Hello to all,
 
I'm opening this new topic in order to make some documentation about the cypress trackpad kext I made and about the cypress PS2 protocol itself.
This will help people understand my code and also help them if they want to customize it or just understand it a little bit more.

It might also help other devs that would like to implement other trackpads ^^, i really think that any C/C++ coder that have an unsupported trackpad can nowadays create a driver for it "easily" (of course some hard work and research to do, but doable ^^' ), i never coded a kext and never coded on PS2 protocol before this first one.

Will try to update this topic each time something revelant comes to my mind.

 

here is some good links to know how "standard" protocol works :

 

http://www.computer-engineering.org/ps2mouse/

http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html
 

 

Cypress Protocol Part:
First lets speak about the cypress protocol: searching on the net, reading linux driver source code and asking some infos to cypress gave me some knowledge on how protocol works :

- like any other PS2 mouse, the cypress one uses standard values for configuring rates/resolution/data mode.

- the only difference to set the trackpad from "standard" protocol to "cypress" packet reporting seems only to rely on the firmware asking. sending the right byte to ask the firmware and then reading the bytes like in linux allowed to "activate" the cypress mode packet reporting.

- so firstly, i re-implemented the same functions present in linux source code for init. (well almost the same, some implicit configuration is done by some linux syscalls).
- once configured properly : init sequence similar to linux one (ask the trackpad its firmware, set rate and res. this can be seen on the function setTouchpadModeByte on my sourcecode), I just send one byte to set data reporting on (0xF4: meaning that from that moment, the mouse will automatically send packets for each events happening on the pad).
 
From there, trackpad will flood the host system with the following :
- each packet is composed of 5 or 8 bytes, depending on the header byte (first one)
- on the contrary of other trackpads (like ALPS or Synaptics), THERE IS NO ACCURATE way (no way to be 100% sure) to determine if a byte is a header byte or not : there is no bit sequence to determine that a byte is header or a byte squence separator between packets to tell that new packet is coming
- The only way to deal with this is to count correctly each received bytes. and try to "validate" a possible header byte by checking consistency (example: if tap bit is on, left or right bit should be on, etc ...)
- And in case of invalid header byte,  empty actual buffer and ask trackpad a resend of last packet (send 0xFE).
- the parsing of the packet content was also given by re-implementing the cypress linux source code.

- for now, have found 2 scenarios in that the trackpad sends 8 bytes packet instead of 5 : on init, and when two fingers are on the trackpad (sending 2 distinct coordinates).

- for 1/3/4/5 fingers, it only sends 5 bytes : specifying on the header the number of fingers but followed only with one finger coordinate.

- so, for a single move on the pad, the trackpad, floods the host with packets containing coordinates.

- once finger/s leave the pad, 500 null bytes (if none is lost) is sent to the host. (don't ask me why)

 

Source code implementation part:

So why have i based my code on VoodooPS2Controller, and more exactly on rehabman's one ?

Because it is a already existing kext that uses and implements ApplePS2Controller (which allows PS2 init/send/receive), and also because it is clean and easy to add new hardware implementation : just added 2 new files at beginning (VoodooPS2CypressTouchPad.cpp and VoodooPS2CypressTouchPad.h) with new class and object instanciation base on the already present classes.

Then implemented cypress init/protocol handling on it.

One thing I have done to manage correctly mouse movement is storing infos about "frames" : each finger move on the trackpad is considered as a packet frame, I store the timer when the frame begins and count packets, if fingers leave pad i clear the counters, if a change on the number of fingers appears (new fingers/removed fingers) I consider it as a new frame.

 

For now that is the only infos that comes to my mind, if somes are working on a PS2 driver, or have questions regarding my code, don't hesitate, ask it here, i will answer and update this post if revelant.

 

Hope that it would help other PS2 devs beginners.

 

 

--

Ulysse31

  • Like 2
Link to comment
Share on other sites

  • 11 months later...

Hi,

I know I am digging up an old thread, but I am currently trying to port the focaltech protocol from linux to VoodooPS2 and have a few questions.

I understand that I have to create a IOHIPointing class which will contain much of the linux protocol. However, I cannot figure out what to do with all the pmouse->private calls from the linux methods.

Could someone who already work on such a port explain me how to replace them ?

Link to comment
Share on other sites

Hi,

 

From what i remember (and briefly checked on cypress linux source 5 min ago ^^) the "pmouse->private" is a kernel pointer where the driver should store its data.

To explain it differently, it is used by the linux driver to keep a pointer to where it "stores" its stuff to have its "data between calls" (at least its this way that ->private is used in cypress linux driver).

You should keep in mind that linux kernel and drivers are written in C, on the other hand, osx kernel and drivers are written in C++, under osx you should just use your private data on your class to store whatever infos you want/need.

 

Hope that I've been helpful ^^.

If you have questions, go ahead.

 

 

Cheers,

 

 

--

Ulysse31

Link to comment
Share on other sites

Thanks !

I knew it would not be that easy to port this driver, but comparing this :

static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
{
	struct ps2dev *ps2dev = &psmouse->ps2dev;

	if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
		psmouse_dbg(psmouse,
				"sending command 0x%02x failed, resp 0x%02x\n",
				value & 0xff, ps2dev->nak);
		if (ps2dev->nak == CYTP_PS2_RETRY)
			return CYTP_PS2_RETRY;
		else
			return CYTP_PS2_ERROR;
	}

#ifdef CYTP_DEBUG_VERBOSE
	psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
			value & 0xff);
#endif

	return 0;
}

to that :

 

UInt8 ApplePS2CypressTouchPad::cypressSendByte(UInt8 cmd)
{
  TPS2Request<1> request;


  request.commands[0].command  = kPS2C_SendMouseCommandAndCompareAck;
  request.commands[0].inOrOut  = cmd & 0xFF;  // & 0xFF is useless but here to hint/guess from where it comes from ^^'


  request.commandsCount = 1;
  assert(request.commandsCount <= countof(request.commands));
  _device->submitRequestAndBlock(&request);


  if (request.commandsCount != 1)
    {
      DEBUG_LOG("CYPRESS: cypressSendByte: RETRY\n");
      return (CYTP_PS2_RETRY);
    }
  return (0);
}

 

make me realize I have a lot to learn...

 

Anyway, I will go step by step until this work.

Link to comment
Share on other sites

Thanks !

 

I knew it would not be that easy to port this driver, but comparing this :

static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
{
	struct ps2dev *ps2dev = &psmouse->ps2dev;

	if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
		psmouse_dbg(psmouse,
				"sending command 0x%02x failed, resp 0x%02x\n",
				value & 0xff, ps2dev->nak);
		if (ps2dev->nak == CYTP_PS2_RETRY)
			return CYTP_PS2_RETRY;
		else
			return CYTP_PS2_ERROR;
	}

#ifdef CYTP_DEBUG_VERBOSE
	psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
			value & 0xff);
#endif

	return 0;
}

to that :

 

UInt8 ApplePS2CypressTouchPad::cypressSendByte(UInt8 cmd)
{
  TPS2Request<1> request;


  request.commands[0].command  = kPS2C_SendMouseCommandAndCompareAck;
  request.commands[0].inOrOut  = cmd & 0xFF;  // & 0xFF is useless but here to hint/guess from where it comes from ^^'


  request.commandsCount = 1;
  assert(request.commandsCount <= countof(request.commands));
  _device->submitRequestAndBlock(&request);


  if (request.commandsCount != 1)
    {
      DEBUG_LOG("CYPRESS: cypressSendByte: RETRY\n");
      return (CYTP_PS2_RETRY);
    }
  return (0);
}

 

make me realize I have a lot to learn...

 

Anyway, I will go step by step until this work.

 

 

Keep in mind that porting a driver is never copy/paste code ^^

Just go step by step as you said.

here some global steps :

1 - read the linux code, do not start from beginning of file but from first call, and follow the calling process. will help understand what it does and how it communicates with the ps2 device.

2 - read a basic osx ps2 driver code, try to find similarities and understand how you make similar actions you've noticed in linux under osx ps2 code.

3 - then here you can start coding/hacking some code ^^.

 

 

Cheers.

Link to comment
Share on other sites

  • 4 weeks later...

Thanks !

 

I knew it would not be that easy to port this driver, but comparing this :

static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
{
	struct ps2dev *ps2dev = &psmouse->ps2dev;

	if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
		psmouse_dbg(psmouse,
				"sending command 0x%02x failed, resp 0x%02x\n",
				value & 0xff, ps2dev->nak);
		if (ps2dev->nak == CYTP_PS2_RETRY)
			return CYTP_PS2_RETRY;
		else
			return CYTP_PS2_ERROR;
	}

#ifdef CYTP_DEBUG_VERBOSE
	psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
			value & 0xff);
#endif

	return 0;
}

to that :

 

UInt8 ApplePS2CypressTouchPad::cypressSendByte(UInt8 cmd)
{
  TPS2Request<1> request;


  request.commands[0].command  = kPS2C_SendMouseCommandAndCompareAck;
  request.commands[0].inOrOut  = cmd & 0xFF;  // & 0xFF is useless but here to hint/guess from where it comes from ^^'


  request.commandsCount = 1;
  assert(request.commandsCount <= countof(request.commands));
  _device->submitRequestAndBlock(&request);


  if (request.commandsCount != 1)
    {
      DEBUG_LOG("CYPRESS: cypressSendByte: RETRY\n");
      return (CYTP_PS2_RETRY);
    }
  return (0);
}

 

make me realize I have a lot to learn...

 

Anyway, I will go step by step until this work.

 

Hello procrastination, have you had any luck with porting the protocol for Focaltech touchpads?

 

I was just thinking of getting to it myself, so maybe you can give me some insight into which problems you encountered?

Thanks

Link to comment
Share on other sites

Well, to tell you the truth I haven't had much time to spend on this since then. The only thing I could tell you is to compare both voodoops2controller .h files and linux input ps2 files to identify corresponding ps2 codes... I will get back to this as soon as possible, but I cannot promise anything right now.

Link to comment
Share on other sites

 Share

×
×
  • Create New...