Ulysse31 Posted January 16, 2014 Share Posted January 16, 2014 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 2 Link to comment Share on other sites More sharing options...
procrastination Posted December 16, 2014 Share Posted December 16, 2014 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 More sharing options...
Ulysse31 Posted December 16, 2014 Author Share Posted December 16, 2014 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 More sharing options...
procrastination Posted December 16, 2014 Share Posted December 16, 2014 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 More sharing options...
Ulysse31 Posted December 16, 2014 Author Share Posted December 16, 2014 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 More sharing options...
baga255 Posted January 10, 2015 Share Posted January 10, 2015 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 More sharing options...
procrastination Posted January 10, 2015 Share Posted January 10, 2015 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 More sharing options...
Recommended Posts