Coding style linux中的第一个内核空间驱动程序

Coding style linux中的第一个内核空间驱动程序,coding-style,raspberry-pi,embedded-linux,hardware-port,Coding Style,Raspberry Pi,Embedded Linux,Hardware Port,我能够使用mmap系统调用控制GPIO,直接从用户空间控制LED操作。现在我想在内核空间实现驱动程序 我正试图为ARM控制器RPi在Linux中的16*2行LCD编写我的第一个内核空间设备驱动程序。 现在我需要为此访问GPIO 在AVR中,我使用如下方式访问端口 #define PORTA *(volatile unsigned char*)0x30 我正在读LLD,它告诉我使用inb()和outb()函数访问I/o端口。 1> 我们可以不使用#定义端口地址来访问GPIO吗 2> 使用in

我能够使用mmap系统调用控制GPIO,直接从用户空间控制LED操作。现在我想在内核空间实现驱动程序

我正试图为ARM控制器RPi在Linux中的16*2行LCD编写我的第一个内核空间设备驱动程序。 现在我需要为此访问GPIO

在AVR中,我使用如下方式访问端口

#define PORTA  *(volatile unsigned char*)0x30
我正在读LLD,它告诉我使用inb()和outb()函数访问I/o端口。

1> 我们可以不使用#定义端口地址来访问GPIO吗

2> 使用inb()和outb()函数控制GPIO有什么好处

请建议。

1)定义的使用通常会简化您的任务。当然,您可以不为您的端口使用define,而是在需要访问端口的任何地方都使用此结构。但是,如果您更改设备的设计,例如,如果您决定将LED连接到端口B,则必须将0x30随处替换为另一个地址。此外,这将降低代码的可读性。或者,您可以声明一个将访问您的端口的函数。如果这样一个简单的函数被声明为
inline
(如果您的编译器支持inline),那么性能上没有差别

2) 使用
inb()
outb()
的优点是程序的可移植性。如果这不是一个问题,那么直接访问您的端口就可以了。

1)使用defines通常可以简化您的任务。当然,您可以不为您的端口使用define,而是在需要访问端口的任何地方都使用此结构。但是,如果您更改设备的设计,例如,如果您决定将LED连接到端口B,则必须将0x30随处替换为另一个地址。此外,这将降低代码的可读性。或者,您可以声明一个将访问您的端口的函数。如果这样一个简单的函数被声明为
inline
(如果您的编译器支持inline),那么性能上没有差别

2) 使用
inb()
outb()
的优点是程序的可移植性。如果这不是问题,那么直接访问您的端口就可以了

在AVR中,我使用如下方式访问端口

#define PORTA  *(volatile unsigned char*)0x30
这是一个不正确的定义,它重载了符号
PORTA

除了将端口地址定义为0x30之外,您还取消了对该位置的引用。
因此,它实际上是一个读取操作,但在名称中没有指示,也就是说,您确实为
read\u PORTA
定义了一个宏

1> 我们可以不使用#定义端口地址来访问GPIO吗

当然你可以(也应该)

在Linux源代码树中的设备寄存器头文件中可以找到类似的语句。在开发一个新的设备驱动程序时,我会为设备的所有寄存器和命令代码寻找一个名为
#defines
的头文件,如果没有可用的文件,就开始编写

2> 使用inb()和outb()函数控制GPIO有什么好处

然后,无论体系结构是使用I/O端口还是内存映射I/O,代码都是正在执行I/O的明确声明。
任何阅读以下内容的人都应该能够推断出发生了什么:

x = inb(PORTA);
与使用宏时的混乱相比:

x = PORTA;
使用重载宏的上述语句将无法通过有能力的编码人员进行的代码审查

您还应该熟悉并使用

在AVR中,我使用如下方式访问端口

#define PORTA  *(volatile unsigned char*)0x30
这是一个不正确的定义,它重载了符号
PORTA

除了将端口地址定义为0x30之外,您还取消了对该位置的引用。
因此,它实际上是一个读取操作,但在名称中没有指示,也就是说,您确实为
read\u PORTA
定义了一个宏

1> 我们可以不使用#定义端口地址来访问GPIO吗

当然你可以(也应该)

在Linux源代码树中的设备寄存器头文件中可以找到类似的语句。在开发一个新的设备驱动程序时,我会为设备的所有寄存器和命令代码寻找一个名为
#defines
的头文件,如果没有可用的文件,就开始编写

2> 使用inb()和outb()函数控制GPIO有什么好处

然后,无论体系结构是使用I/O端口还是内存映射I/O,代码都是正在执行I/O的明确声明。
任何阅读以下内容的人都应该能够推断出发生了什么:

x = inb(PORTA);
与使用宏时的混乱相比:

x = PORTA;
使用重载宏的上述语句将无法通过有能力的编码人员进行的代码审查


您还应该熟悉并使用。

我认为inb()使用i/o地址空间来读取端口,而不是使用内存映射空间。您所说的程序可移植性是什么意思?请阅读本文了解定义。假设您从同一供应商切换到另一个CPU型号,或兼容的型号,它没有单独的IO地址空间,但提供与原始产品相同地址的端口。然后,您只需使用编译器选项来告诉它您正在为其构建程序的体系结构,它就可以无缝地在两种不同的访问方法之间切换。当然,当我们谈论嵌入式开发时,这种灵活性很少有一席之地,但仍然使用编译器内置可以节省您的开发成本。无论如何,你应该和你的案子的文件核对一下。这个问题或多或少是一般性的,所以我提供了一个一般性的答案。在做出选择时,您应该始终考虑所有细节。我认为inb()使用i/o地址空间来读取端口,而不是使用内存映射空间。您所说的程序可移植性是什么意思?请阅读此部分了解t