5

I have a Cincoze DE-1000 industrial PC, that features a Fintek F81866A chipset. I have to manage the DIO pins to read the input from a phisical button and to set on/off a LED. I have experience in C++ programming, but not at low/hardware level.

On the documentation accompanying the PC, there is the following C code:

#define AddrPort 0x4E
#define DataPort 0x4F

//<Enter the Extended Function Mode>
WriteByte(AddrPort, 0x87)
WriteByte(AddrPort, 0x87) //Must write twice to entering Extended mode

//<Select Logic Device>
WriteByte(AddrPort, 0x07)
WriteByte(DataPort, 0x06)
//Select logic device 06h

//<Input Mode Selection> //Set GP74 to GP77 input mode
WriteByte(AddrPort, 0x80) //Select configuration register 80h
WriteByte(DataPort, 0x0X)
//Set (bit 4~7) = 0 to select GP 74~77 as Input mode.

//<input Value>
WriteByte(AddrPort, 0x82) // Select configuration register 82h
ReadByte(DataPort, Value) // Read bit 4~7(0xFx)= GP74 ~77 as High.

//<Leave the Extended Function Mode>
WriteByte(AddrPort, 0xAA)

As far as I understood, the above code should read the value of the four input PINs (so it should read 1 for each PIN), but I am really struggling to understand how it actually works. I have understood the logic (selecting an address and reading/writing an hex value to it), but I cannot figure out what kind of C instructions WriteByte() and ReadByte() are. Also, I do not understand where Value in the line ReadByte(DataPort, Value) comes from. It should read the 4 PINs all together, so it should be some kind of "byte" type and it should contain 1 in its bits 4-7, but again I cannot really grasp the meaning of that line.

I have found an answer for a similar chip, but it did not help me in understanding.

Please advice me or point me to some relevant documentation.

Giorgio R
  • 85
  • 1
  • 9

2 Answers2

7

That chip looks like a fairly typical Super I/O controller, which is basically the hub where all of the "slow" peripherals are combined into a single chipset.

Coreboot has a wiki page that talks about how to access the super I/O.


On the PC architecture, Port I/O is accomplished using special CPU instructions, namely in and out. These are privileged instructions, which can only be used from a kernel-mode driver (Ring 0), or a userspace process which has been given I/O privileges.

Luckily, this is easy in Linux. Check out the man page for outb and friends.

You use ioperm(2) or alternatively iopl(2) to tell the kernel to allow the user space application to access the I/O ports in question. Failure to do this will cause the application to receive a segmentation fault.

So we could adapt your function into a Linux environment like this:

/* Untested: Use at your own risk! */
#include <sys/io.h>
#include <stdio.h>

#define ReadByte(port)          inb(port)
#define WriteByte(port, val)    outb(val, port)

int main(void)
{
    if (iopl(3) < 0) {
        fprintf(stderr, "Failed to get I/O privileges (are you root?)\n");
        return 2;
    }


    /* Your code using ReadByte / WriteByte here */
}

Warning

You should be very careful when using this method to talk directly to the Super IO, because your operating system almost certainly has device drivers that are also talking to the chip.

The right way to accomplish this is to write a device driver that properly coordinates with other kernel code to avoid concurrent access to the device.

The Linux kernel provides GPIO access to at least some Super I/O devices; it should be straightforward to port one of these to your platform. See this pull request for the IT87xx chipset.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • Hi Jonathon, thank you for your support. I successfully compiled the code and I could detect the press of a physical button. By the way, the platform I am working on is Linux (Debian Stretch). I understand your warning: my first attempt was to use /sys/classgpio, but it constantly failed. I try to "activate" the pins with `echo 74 > /sys/class/gpio/export` (74 is the number in the documentation, I even tried any number between 0 to 10000 without any success). I suppose that the Fintek board is not supported. – Giorgio R Oct 08 '18 at 10:43
2

WriteByte() and ReadByte() are not part of the C language. By the looks of things, they are functions intended to be placeholders for some form of system call for the OS kernel port IO (not macros doing memory mapped IO directly as per a previous version of this answer).

The prototypes for the functions would be something along the lines of:

#include <stdint.h>
void WriteByte(unsigned port, uint8_t value);
void ReadByte(unsigned port, uint8_t *value);

Thus the Value variable would be a pointer to an 8 bit unsigned integer (unsigned char could also be used), something like:

uint8_t realValue;
uint8_t *Value = &realValue;

Of course it would make much more sense to have Value just be a uint8_t and have ReadByte(DataPort, &Value). But then the example code also doesn't have any semicolons, so was probably never anything that actually ran. Either way, this is how Value would contain the data you are looking for.

I also found some more documentation of the registers here - https://www.electronicsdatasheets.com/download/534cf560e34e2406135f469d.pdf?format=pdf

Hope this helps.

Graeme
  • 2,971
  • 21
  • 26
  • You're assuming that the hardware he's accessing is using *Memory-mapped I/O*. This code will certainly crash if you attempt to use it from a user-space application on a protected-mode OS like Linux or Windows. – Jonathon Reinhart Oct 05 '18 at 21:40
  • @JonathonReinhart Correct. I was assuming no OS, but this is probably not the case `WriteByte()` and `ReadByte()` are more likely functions and `Value` intended to be a pointer. – Graeme Oct 05 '18 at 21:48
  • The point is that these are not memory-mapped registers at all. They are I/O ports, which are accessed via separate instructions on x86. Please see [my answer above](https://stackoverflow.com/a/52673619/119527). – Jonathon Reinhart Oct 05 '18 at 21:59
  • @JonathonReinhart, thanks, I saw your answer. But the OP was asking where the `Value` variable comes from as it is not declared in the example code. I was trying to shed some light on that. – Graeme Oct 05 '18 at 22:03
  • You're right, my definition of `ReadByte` is not compatible with the OP's usage. – Jonathon Reinhart Oct 05 '18 at 23:31
  • Thank you Graeme, your input was indeed helpful – Giorgio R Oct 08 '18 at 10:40