我有一台Cincoze DE-1000工业 PC,它配备了Fintek F81866A芯片组。我必须管理 DIO 引脚才能从物理按钮读取输入并设置开/关 LED。我有 C++ 编程的经验,但不是低级/硬件级的。
在 PC 随附的文档中,有以下 C 代码:
#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)
Run Code Online (Sandbox Code Playgroud)
据我所知,上面的代码应该读取四个输入 PIN 的值(所以它应该为每个 PIN 读取 1),但我真的很难理解它是如何工作的。我理解了逻辑(选择一个地址和读/写的十六进制值的话),但我想不出什么类C的说明WriteByte()和ReadByte()是。另外,我不明白Value该行ReadByte(DataPort, Value)来自哪里。它应该一起读取 4 个 PIN,所以它应该是某种“字节”类型,并且它的第 4-7 位应该包含 1,但我再次无法真正理解该行的含义。
请给我建议或指向我一些相关的文档。
该芯片看起来像一个相当典型的超级 I/O控制器,它基本上是所有“慢速”外围设备组合成单个芯片组的集线器。
Coreboot 有一个 wiki 页面,讨论如何访问超级 I/O。
在 PC 架构上,端口 I/O是使用特殊的 CPU 指令完成的,即in和out。这些是特权指令,只能从内核模式驱动程序(Ring 0)或已被授予 I/O 权限的用户空间进程中使用。
幸运的是,这在 Linux 中很容易。查看和朋友的手册页outb。
您可以使用 ioperm(2) 或 iopl(2) 来告诉内核允许用户空间应用程序访问有问题的 I/O 端口。不这样做将导致应用程序收到分段错误。
因此,我们可以将您的功能调整到这样的 Linux 环境中:
/* 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 */
}
Run Code Online (Sandbox Code Playgroud)
在使用这种方法直接与 Super IO 对话时,您应该非常小心,因为您的操作系统几乎肯定有设备驱动程序也在与芯片对话。
实现这一点的正确方法是编写一个与其他内核代码正确协调的设备驱动程序,以避免并发访问设备。
Linux 内核至少提供对一些超级 I/O 设备的 GPIO 访问;将其中之一移植到您的平台应该很简单。请参阅此 IT87xx 芯片组的拉取请求。