我在编写Linux设备驱动程序时阅读了this excellent DIY article,但我仍然没有在这里看到一个主要项目的“森林穿过树”。最终,最终用户软件(在用户空间中)需要与硬件通信(设备驱动程序驱动 /包装/适应)。硬件由电驱动,因此软件命令需要转换成高/低信号(1和0),这些信号被推出到电路上并进入连接的硬件。一个愚蠢的简单例子:
# Send a connected LED device a command to turn on at the software layer:
led.turnOn();
# In the device driver, somehow, translate this to 0x01 (1, or 00000001):
void turnOn() {
int signal = 1;
# Now, *somehow*, push this to the hardware with the following pinout (see below):
}
# Pinout
0 ----------------> /----------\
0 ----------------> | |
0 ----------------> | |
0 ----------------> | Hardware |
0 ----------------> | |
0 ----------------> | |
0 ----------------> | |
1 ----------------> \----------/
我没有看到的是:在设备驱动程序C代码中,我如何读取/写入来自底层硬件设备的字节/数据? < / p>
我能看到的唯一理论是,因为Linux设备被视为用户空间的“文件”(dev/led
),或许将数据(如0x01)写入dev/led
是如何我们向连接的设备发送命令;也许从设备读取数据就是我们如何从中读取数据。
我是朝着正确的方向前进,还是偏离轨道?
答案 0 :(得分:3)
这实际上取决于设备的性质以及它如何连接到系统 - 它可以是内存映射,或映射到某种可寻址的I / O空间,或者在总线上,如PCI-e或例如,USB。重点是在驱动程序中对此进行抽象,以便程序员不必关心低级细节。
例如,对于PCI设备,电路板可能会映射到物理地址范围。在此范围内,您可以访问某些寄存器来控制硬件。假设您有一个带有单个32位寄存器的简单I / O卡,并且该卡映射到物理地址0xf0000000
。该寄存器用于控制32个LED输出,您想打开LED 0:
volatile uint32_t * const my_card_register = (uint32_t *) 0xf0000000;
// address of PCI card register
*my_card_register |= 0x00000001; // set bit 0 in register to turn on LED