唯客微博客

专注于计算机,嵌入式领域的技术

0%

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#define	EPERM		 1	/* Operation not permitted */           操作不允许
#define ENOENT 2 /* No such file or directory */ 文件或路径不存在
#define ESRCH 3 /* No such process */ 进程不存在
#define EINTR 4 /* Interrupted system call */ 中断的系统调用
#define EIO 5 /* I/O error */ I/O错误
#define ENXIO 6 /* No such device or address */ 设备或地址不存在
#define E2BIG 7 /* Argument list too long */ 参数列表过长
#define ENOEXEC 8 /* Exec format error */ 执行格式错误
#define EBADF 9 /* Bad file number */ 错误的文件编码
#define ECHILD 10 /* No child processes */ 子进程不存在
#define EAGAIN 11 /* Try again */ 重试,非阻塞socket一般在缓冲区无数据时返回,阻塞socket标识超时
#define ENOMEM 12 /* Out of memory */ 内存不足
#define EACCES 13 /* Permission denied */ 没有权限
#define EFAULT 14 /* Bad address */ 地址错误
#define ENOTBLK 15 /* Block device required */ 需要块设备
#define EBUSY 16 /* Device or resource busy */ 设备或资源忙
#define EEXIST 17 /* File exists */ 文件已经存在
#define EXDEV 18 /* Cross-device link */ 跨设备链路
#define ENODEV 19 /* No such device */ 设备不存在
#define ENOTDIR 20 /* Not a directory */ 文件夹路径不存在
#define EISDIR 21 /* Is a directory */ 是文件夹路径
#define EINVAL 22 /* Invalid argument */ 无效参数
#define ENFILE 23 /* File table overflow */ 文件表溢出
#define EMFILE 24 /* Too many open files */ 打开的文件描过多
#define ENOTTY 25 /* Not a typewriter */ 非打字机
#define ETXTBSY 26 /* Text file busy */ 文本文件忙,缓冲区被占用
#define EFBIG 27 /* File too large */ 文件过大
#define ENOSPC 28 /* No space left on device */ 设备没有剩余空间
#define ESPIPE 29 /* Illegal seek */ 非法查询
#define EROFS 30 /* Read-only file system */ 文件系统只读
#define EMLINK 31 /* Too many links */ 连接过多,超过系统限制
#define EPIPE 32 /* Broken pipe */ 管道破裂
#define EDOM 33 /* Math argument out of domain of func */ 参数超出函数域
#define ERANGE 34 /* Math result not representable */ 结果无法表示
#define EDEADLK 35 /* Resource deadlock would occur */ 资源将发生死锁
#define ENAMETOOLONG 36 /* File name too long */ 文件名过长
#define ENOLCK 37 /* No record locks available */ 没有可用的记录锁
#define ENOSYS 38 /* Function not implemented */ 函数未实现
#define ENOTEMPTY 39 /* Directory not empty */ 文件夹非空
#define ELOOP 40 /* Too many symbolic links encountered */ 遇到太多的符号连接
#define EWOULDBLOCK EAGAIN /* Operation would block */ 操作将阻塞
#define ENOMSG 42 /* No message of desired type */ 没有符合需求类型的消息
#define EIDRM 43 /* Identifier removed */ 标识符已移除
#define ECHRNG 44 /* Channel number out of range */ 通道编号超出范围
#define EL2NSYNC 45 /* Level 2 not synchronized */ Level 2 未同步
#define EL3HLT 46 /* Level 3 halted */ Level 3 停止
#define EL3RST 47 /* Level 3 reset */ Level 3 重置
#define ELNRNG 48 /* Link number out of range */ 连接数量超出范围
#define EUNATCH 49 /* Protocol driver not attached */ 协议驱动程序未附加
#define ENOCSI 50 /* No CSI structure available */ 无CSI结构可用
#define EL2HLT 51 /* Level 2 halted */ Level 2 停止
#define EBADE 52 /* Invalid exchange */ 无效的交换
#define EBADR 53 /* Invalid request descriptor */ 无效的请求描述
#define EXFULL 54 /* Exchange full */ 交换完全
#define ENOANO 55 /* No anode */ 无阳极
#define EBADRQC 56 /* Invalid request code */ 无效的请求码
#define EBADSLT 57 /* Invalid slot */ 无效的插槽
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */ 错误的字体文件格式
#define ENOSTR 60 /* Device not a stream */ 设备非流
#define ENODATA 61 /* No data available */ 无有效数据
#define ETIME 62 /* Timer expired */ 计时器到期
#define ENOSR 63 /* Out of streams resources */ 超出流资源
#define ENONET 64 /* Machine is not on the network */ 机器不在网络
#define ENOPKG 65 /* Package not installed */ 未安装包
#define EREMOTE 66 /* Object is remote */ 对象是远程
#define ENOLINK 67 /* Link has been severed */ 链接正在服务中
#define EADV 68 /* Advertise error */ 广告错误
#define ESRMNT 69 /* Srmount error */ 这个错误是RFS特定的。 当远程计算机仍在装载资源时尝试停止RFS,或者当资源使用不包含具有当前装入的资源的远程计算机的客户机列表重新进行读取时发生。
#define ECOMM 70 /* Communication error on send */ 发送过程中通讯错误
#define EPROTO 71 /* Protocol error */ 协议错误
#define EMULTIHOP 72 /* Multihop attempted */ 多跳尝试
#define EDOTDOT 73 /* RFS specific error */ RFS特殊错误
#define EBADMSG 74 /* Not a data message */ 不是数据类型的消息
#define EOVERFLOW 75 /* Value too large for defined data type */ 对指定的数据类型来说值太大
#define ENOTUNIQ 76 /* Name not unique on network */ 网络上名字不唯一
#define EBADFD 77 /* File descriptor in bad state */ 文件描述符状态错误
#define EREMCHG 78 /* Remote address changed */ 远程地址改变
#define ELIBACC 79 /* Can not access a needed shared library */ 无法访问需要的共享库
#define ELIBBAD 80 /* Accessing a corrupted shared library */ 访问损坏的共享库
#define ELIBSCN 81 /* .lib section in a.out corrupted */ 库部分a.out损坏
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ 试图连接过多的共享库
#define ELIBEXEC 83 /* Cannot exec a shared library directly */ 不能直接运行共享库
#define EILSEQ 84 /* Illegal byte sequence */ 非法字节序
#define ERESTART 85 /* Interrupted system call should be restarted */ 硬重新启动被中断的的系统调用
#define ESTRPIPE 86 /* Streams pipe error */ 流管错误
#define EUSERS 87 /* Too many users */ 用户过多
#define ENOTSOCK 88 /* Socket operation on non-socket */ 在非套接字上进行套接字操作
#define EDESTADDRREQ 89 /* Destination address required */ 需要目标地址
#define EMSGSIZE 90 /* Message too long */ 消息过长
#define EPROTOTYPE 91 /* Protocol wrong type for socket */ 错误的协议类型
#define ENOPROTOOPT 92 /* Protocol not available */ 无效协议
#define EPROTONOSUPPORT 93 /* Protocol not supported */ 协议不支持
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ socket类型不支持
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ 操作不支持传输端点
#define EPFNOSUPPORT 96 /* Protocol family not supported */ 不支持的协议族
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ 协议不支持地址群
#define EADDRINUSE 98 /* Address already in use */ 地址被占用
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ 无法分配请求的地址
#define ENETDOWN 100 /* Network is down */ 网络关闭
#define ENETUNREACH 101 /* Network is unreachable */ 网络不可达
#define ENETRESET 102 /* Network dropped connection because of reset */ 网络复位点开链接
#define ECONNABORTED 103 /* Software caused connection abort */ 软件导致的连接终止
#define ECONNRESET 104 /* Connection reset by peer */ 连接被对端复位
#define ENOBUFS 105 /* No buffer space available */ 没有可用的缓冲空间
#define EISCONN 106 /* Transport endpoint is already connected */ 传输端点已连接
#define ENOTCONN 107 /* Transport endpoint is not connected */ 传输端点未连接
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ 传输端点关闭后不允许再发送
#define ETOOMANYREFS 109 /* Too many references: cannot splice */ 引用过多:无法接合
#define ETIMEDOUT 110 /* Connection timed out */ 连接超时
#define ECONNREFUSED 111 /* Connection refused */ 连接被拒绝
#define EHOSTDOWN 112 /* Host is down */ host关闭
#define EHOSTUNREACH 113 /* No route to host */ 无法路由到主机
#define EALREADY 114 /* Operation already in progress */ 操作已在进程中
#define EINPROGRESS 115 /* Operation now in progress */ 操作正在进行
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */ 远程I/O错误
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ECANCELED 125 /* Operation Canceled */
#define ENOKEY 126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service */

likely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likely(value))等价于if (value) if (unlikely(value))等价于if (value)

也就是说likely()和unlikely()从阅读和理解的角度是一样的。 这两个宏在内核中定义如下:

1
2
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。 __buildin_expect((x), 1)表示x的值为真的可能性更大. __buildin_expect((x), 0)表示x的值为假的可能性更大. 也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。

  尽管 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 内存的情况进行了优化。

1 申请I/O 内存:

  I/O 内存区在使用前必须先分配。分配内存区的函数接口在<linux/ioport.h>定义中:

1
2
3
4
/* request_mem_region分配一个开始于start,len字节的I/O内存区。分配成功,返回一个非NULL指针;
否则返回NULL。系统当前所有I/O内存分配信息都在/proc/iomem文件中列出,你分配失败时,可以看看该文件,
看谁先占用了该内存区 */
struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
## 2 映射:   在访问I/O内存之前,分配I/O内存并不是唯一要求的步骤,你还必须保证内核可存取该I/O内存。访问I/O内存并不只是简单解引用指针,在许多体系中,I/O 内存无法以这种方式直接存取。因此,还必须通过ioremap 函数设置一个映射。
1
2
3
/* ioremap用于将I/O内存区映射到虚拟地址。参数phys_addr为要映射的I/O内存起始地址,
参数size为要映射的I/O内存的大小,返回值为被映射到的虚拟地址 */
void *ioremap(unsigned long phys_addr, unsigned long size);
阅读全文 »

## 1 申请I/O 端⼝: 在驱动还没独占设备之前,不应对端⼝进⾏操作。内核提供了⼀个注册接⼝,以允许驱动声明其需要的端⼝:

1
2
3
4
/* request_region告诉内核:要使⽤first开始的n个端⼝。参数name为设备名。
如果分配成功返回值是⾮NULL;否则无法使用需要的端口(/proc/ioports包含了系统当前所有端口的分配信息,
若request_region分配失败时,可以查看该文件,看谁先用了你要的端口) */
struct resource *request_region(unsigned long first, unsigned long n, const char *name);
## 2 访问IO端⼝: 在驱动成功请求到I/O 端⼝后,就可以读写这些端⼝了。⼤部分硬件会将8位、16位和32位端⼝区分开,⽆法像访问内存那样混淆使⽤。驱动程序必须调⽤不同的函数来访问不同⼤⼩的端⼝。 Linux 内核头⽂件(体系依赖的头⽂件<asm/io.h>) 定义了下列内联函数来存取I/O端⼝:
1
2
3
4
5
6
7
8
9
10
/* inb/outb:读/写字节端⼝(8位宽)。有些体系将port参数定义为unsigned long;
⽽有些平台则将它定义为unsigned short。inb的返回类型也是依赖体系的 */
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
/* inw/outw:读/写字端⼝(16位宽) */
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
/* inl/outl:读/写32位端⼝。longword也是依赖体系的,有的体系为unsigned long;⽽有的为unsigned int */
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);
## 3 释放IO端⼝:
1
2
3
/* ⽤完I/O端⼝后(可能在模块卸载时),应当调⽤release_region将I/O端⼝返还给系统。
参数start和n应与之前传递给request_region⼀致 */
void release_region(unsigned long start, unsigned long n);

阅读全文 »

一般我们会用到 kmalloc()、kzalloc()、vmalloc() 等,下面我们介绍一下这些函数的使用以及它们之间的区别。

kmalloc()

函数原型:

1
void *kmalloc(size_t size, gfp_t flags)
kmalloc() 申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因为存在较简单的转换关系,所以对申请的内存大小有限制,不能超过128KB。    较常用的 flags(分配内存的方法): + GFP_ATOMIC: 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断; + GFP_KERNEL: 正常分配内存; + GFP_DMA: 给 DMA 控制器分配内存,需要使用该标志(DMA要求分配虚拟地址和物理地址连续)。 flags 的参考用法:  |– 进程上下文,可以睡眠     GFP_KERNEL  |– 进程上下文,不可以睡眠    GFP_ATOMIC  |  |– 中断处理程序       GFP_ATOMIC  |  |– 软中断          GFP_ATOMIC  |  |– Tasklet         GFP_ATOMIC  |– 用于DMA的内存,可以睡眠   GFP_DMA | GFP_KERNEL  |– 用于DMA的内存,不可以睡眠  GFP_DMA |GFP_ATOMIC

阅读全文 »

1
2
3
4
5
6
7
8
9
10
11
/*
* The PCI interface treats multi-function devices as independent
* devices. The slot/function address of each device is encoded
* in a single byte as follows:
*
* 7:3 = slot
* 2:0 = function
*/
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
1
2
3
4
5
struct pci_dev *dev

BusNumber = dev->bus->number;
SlotNumber = PCI_SLOT(dev->devfn);
FuncNumber = PCI_FUNC(dev->devfn);

1
2
3
4
5
6
struct pci_device_id {
__u32 vendor, device; /* 厂商和设备ID,Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* 子系统和设备ID,Subsystem ID's or PCI_ANY_ID */
__u32 class, class_mask; /* 类、子类、prog-if三元组,(class,subclass,prog-if) triplet */
kernel_ulong_t driver_data; /* 驱动私有数据,Data private to the driver */
};

pci_device_id 用MODULE_DEVICE_TABLE宏导出到用户空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
struct pci_bus {
/* 链表元素node:对于PCI根总线而言,其pci_bus结构通过node成员链接到本节一开始所述的根总线链表中,根总线链表
的表头由一个list_head类型的全局变量pci_root_buses所描述。而对于非根pci总线,其pci_bus结构通过node成员链接
到其父总线的子总线链表children中*/
struct list_head node;
/*parent指针:指向该pci总线的父总线,即pci桥所在的那条总线*/
struct pci_bus *parent;
/*children指针:描述了这条PCI总线的子总线链表的表头。这条PCI总线的所有子总线都通过上述的node链表元素链接成一
条子总线链表,而该链表的表头就由父总线的children指针所描述*/
struct list_head children;
/* list of devices on this bus */
struct list_head devices;
/* devices链表头:描述了这条PCI总线的逻辑设备链表的表头。除了链接在全局PCI设备链表中之外,每一个PCI逻辑设备也
通过其 pci_dev结构中的bus_list成员链入其所在PCI总线的局部设备链表中,而这个局部的总线设备链表的表头就由
pci_bus结构中的 devices成员所描述*/
struct pci_dev *self;
/* 资源指针数组:指向应路由到这条pci总线的地址空间资源,通常是指向对应桥设备的pci_dev结构中的资源数组resource[10:7]*/
struct resource *resource[PCI_BUS_NUM_RESOURCES];
/* 指针ops:指向一个pci_ops结构,表示这条pci总线所使用的配置空间访问函数*/
struct pci_ops *ops;
/* 无类型指针sysdata:指向系统特定的扩展数据*/
void *sysdata;
/* 指针procdir:指向该PCI总线在/proc文件系统中对应的目录项*/
struct proc_dir_entry *procdir;
/* number:这条PCI总线的总线编号(bus number),取值范围0-255 */
unsigned char number;
/* primary:表示引出这条PCI总线的“桥设备的主总线”(也即桥设备所在的PCI总线)编号,取值范围0-255*/
unsigned char primary;/* secondary:表示引出这条PCI总线的桥设备的次总线号,因此secondary成员总是等于number成员的值。取值范围0-255*/
unsigned char secondary;
/* subordinate:这条PCI总线的下属PCI总线(Subordinate pci bus)的总线编号最大值,它应该等于引出这条PCI总线的桥设备的subordinate值*/
unsigned char subordinate;
/* name[48]:这条PCI总线的名字字符串*/
char name[48];
unsigned short bridge_ctl;
unsigned short pad2;
struct device *bridge;
struct device class_dev;
struct bin_attribute *legacy_io;
struct bin_attribute *legacy_mem;
};

每种类的PCI设备都可以用结构类型pci_dev来描述。更为准确地说,应该是每一个PCI功能,即PCI逻辑设备都唯一地对应有一个pci_dev设备描述符。该数据结构的部分定义如下(include/linux/pci.h):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
struct pci_dev {
/* 总线设备链表元素bus_list:每一个pci_dev结构除了链接到全局设备链表中外,还会通过这个成员连接到
其所属PCI总线的设备链表中。每一条PCI总线都维护一条它自己的设备链表视图,以便描述所有连接在该
PCI总线上的设备,其表头由PCI总线的pci_bus结构中的 devices成员所描述t*/
struct list_head bus_list;
/* 总线指针bus:指向这个PCI设备所在的PCI总线的pci_bus结构。因此,对于桥设备而言,bus指针将指向
桥设备的主总线(primary bus),也即指向桥设备所在的PCI总线*/
struct pci_bus *bus;
/* 指针subordinate:指向这个PCI设备所桥接的下级总线。这个指针成员仅对桥设备才有意义,而对于一般
的非桥PCI设备而言,该指针成员总是为NULL*/
struct pci_bus *subordinate;
/* 无类型指针sysdata:指向一片特定于系统的扩展数据*/
void *sysdata;
/* 指针procent:指向该PCI设备在/proc文件系统中对应的目录项*/
struct proc_dir_entry *procent;
/* devfn:这个PCI设备的设备功能号,也成为PCI逻辑设备号(0-255)。其中bit[7:3]是物理设备号(取值
范围0-31),bit[2:0]是功能号(取值范围0-7)。 */
unsigned int devfn;
/* vendor:这是一个16无符号整数,表示PCI设备的厂商ID*/
unsigned short vendor;
/*device:这是一个16无符号整数,表示PCI设备的设备ID */
unsigned short device;
/* subsystem_vendor:这是一个16无符号整数,表示PCI设备的子系统厂商ID*/
unsigned short subsystem_vendor;
/* subsystem_device:这是一个16无符号整数,表示PCI设备的子系统设备ID。*/
unsigned short subsystem_device;
/* class:32位的无符号整数,表示该PCI设备的类别,其中,bit[7:0]为编程接口,bit[15:8]为子类
别代码,bit [23:16]为基类别代码,bit[31:24]无意义。显然,class成员的低3字节刚好对应与PCI配
置空间中的类代码*/
unsigned int class;
/* hdr_type:8位符号整数,表示PCI配置空间头部的类型。其中,bit[7]=1表示这是一个多功能设备,
bit[7]=0表示这是一个单功能设备。Bit[6:0]则表示PCI配置空间头部的布局类型,值00h表示这是一
个一般PCI设备的配置空间头部,值01h表示这是一个PCI-to-PCI桥的配置空间头部,值02h表示CardBus桥
的配置空间头部*/
u8 hdr_type;
/* rom_base_reg:8位无符号整数,表示PCI配置空间中的ROM基地址寄存器在PCI配置空间中的位置。
ROM基地址寄存器在不同类型的PCI配置空间头部的位置是不一样的,对于type 0的配置空间布局,ROM基
地址寄存器的起始位置是30h,而对于PCI-to-PCI桥所用的type 1配置空间布局,ROM基地址寄存器的起始
位置是38h*/
u8 rom_base_reg;
/* 指针driver:指向这个PCI设备所对应的驱动程序定义的pci_driver结构。每一个pci设备驱动程序都必须定
义它自己的pci_driver结构来描述它自己。*/
struct pci_driver *driver;
/*dma_mask:用于DMA的总线地址掩码,一般来说,这个成员的值是0xffffffff。数据类型dma_addr_t定义在
include/asm/types.h中,在x86平台上,dma_addr_t类型就是u32类型*/
u64 dma_mask;
/* 当前操作状态 */
pci_power_t current_state;
/* 通用的设备接口*/
struct device dev;
/* 无符号的整数irq:表示这个PCI设备通过哪根IRQ输入线产生中断,一般为0-15之间的某个值 */
unsigned int irq;
/*表示该设备可能用到的资源,包括:I/O断口区域、设备内存地址区域以及扩展ROM地址区域。*/
struct resource resource[DEVICE_COUNT_RESOURCE];
/* 配置空间的大小 */
int cfg_size;
/* 透明 PCI 桥 */
unsigned int transparent:1;
/* 多功能设备*/
unsigned int multifunction:1;
/* 设备是主设备*/
unsigned int is_busmaster:1;
/* 设备不使用msi*/
unsigned int no_msi:1;
/* 配置空间访问形式用块的形式 */
unsigned int block_ucfg_access:1;
/* 在挂起时保存配置空间*/
u32 saved_config_space[16];
/* sysfs ROM入口的属性描述*/
struct bin_attribute *rom_attr;
/* 能显示rom 属性*/
int rom_attr_enabled;
/* 资源的sysfs文件*/
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE];

};

> 以下内容摘自内核初始化优化宏 ,初始化顺序, __init,__devexit等, 本文仅作为笔记保存。

内核使用了大量不同的宏来标记具有不同作用的函数和数据结构。如宏__init 、__devinit 等。这些宏在include/linux/init.h 头文件中定义。编译器通过这些宏可以把代码优化放到合适的内存位置,以减少内存占用和提高内核效率。

下面是一些常用的宏:

__init

标记内核启动时使用的初始化代码,内核启动完成后不再需要。以此标记的代码位于.init.text 内存区域。

阅读全文 »