1 | #define EPERM 1 /* Operation not permitted */ 操作不允许 |
Linux驱动开发杂记(0x0A) - errno含义
1 |
1 | #define EPERM 1 /* Operation not permitted */ 操作不允许 |
likely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likely(value))等价于if (value) if (unlikely(value))等价于if (value)
也就是说likely()和unlikely()从阅读和理解的角度是一样的。
这两个宏在内核中定义如下:
这里的__built_expect()函数是gcc(version >=
2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。
__buildin_expect((x), 1)表示x的值为真的可能性更大. __buildin_expect((x),
0)表示x的值为假的可能性更大.
也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。1
2#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
尽管 I/O 端口在x86世界中非常流行,但是用来和设备通讯的主要机制是通过内存映射的寄存器和设备内存,两者都称为I/O 内存,因为寄存器和内存之间的区别对软件是透明的。 I/O 内存仅仅是一个类似于RAM 的区域,处理器通过总线访问该区域,以实现对设备的访问。同样,读写这个区域是有边际效应。 根据计算机体系和总线不同,I/O 内存可分为可以或者不可以通过页表来存取。若通过页表存取,内核必须先重新编排物理地址,使其对驱动程序可见,这就意味着在进行任何I/O操作之前,你必须调用ioremap;如果不需要页表,I/O内存区域就类似于I/O端口,你可以直接使用适当的I/O函数读写它们。 由于边际效应的缘故,不管是否需要 ioremap,都不鼓励直接使用I/O内存指针,而应使用专门的I/O内存操作函数。这些I/O内存操作函数不仅在所有平台上是安全,而且对直接使用指针操作 I/O 内存的情况进行了优化。
I/O 内存区在使用前必须先分配。分配内存区的函数接口在<linux/ioport.h>定义中:
1 | /* request_mem_region分配一个开始于start,len字节的I/O内存区。分配成功,返回一个非NULL指针; |
1 | /* ioremap用于将I/O内存区映射到虚拟地址。参数phys_addr为要映射的I/O内存起始地址, |
## 1 申请I/O 端⼝: 在驱动还没独占设备之前,不应对端⼝进⾏操作。内核提供了⼀个注册接⼝,以允许驱动声明其需要的端⼝:
1 | /* request_region告诉内核:要使⽤first开始的n个端⼝。参数name为设备名。 |
1 | /* inb/outb:读/写字节端⼝(8位宽)。有些体系将port参数定义为unsigned long; |
1 | /* ⽤完I/O端⼝后(可能在模块卸载时),应当调⽤release_region将I/O端⼝返还给系统。 |
一般我们会用到 kmalloc()、kzalloc()、vmalloc() 等,下面我们介绍一下这些函数的使用以及它们之间的区别。
函数原型:
1 | void *kmalloc(size_t size, gfp_t flags); |
1 | /* |
1 | struct pci_dev *dev |
1 | struct pci_device_id { |
pci_device_id 用MODULE_DEVICE_TABLE宏导出到用户空间。
1 | struct pci_bus { |
每种类的PCI设备都可以用结构类型pci_dev来描述。更为准确地说,应该是每一个PCI功能,即PCI逻辑设备都唯一地对应有一个pci_dev设备描述符。该数据结构的部分定义如下(include/linux/pci.h):
1 | struct pci_dev { |
> 以下内容摘自内核初始化优化宏 ,初始化顺序, __init,__devexit等, 本文仅作为笔记保存。
内核使用了大量不同的宏来标记具有不同作用的函数和数据结构。如宏__init 、__devinit 等。这些宏在include/linux/init.h 头文件中定义。编译器通过这些宏可以把代码优化放到合适的内存位置,以减少内存占用和提高内核效率。
下面是一些常用的宏:
标记内核启动时使用的初始化代码,内核启动完成后不再需要。以此标记的代码位于.init.text 内存区域。