终于可以清闲下来打理一下我的blog了,台资企业真的事情很多很烦……
前几篇文章对字符设备有个简单介绍,并以简单的一个字符设备驱动作结尾,其实linux上大部分驱动程序都是字符设备程序,Linux源码中也可以看到很多的字符设备驱动,所以供学习的代码还是很多的。
这一节本想说一下如何测试设备驱动,但是因为最近看了看内核链标,所以称还记的比较清楚赶紧记录下来。有不到位的地方烦请指正。
Linux 内核链表
链表的简单介绍:
链表是线性表的实现方式之一,是一种常用的数据结构,用来组织一系列有序数据,并通过指针将这些有序数列链成一条数据链。相对于数组来说,它有良好的伸缩性,可以动态的添加或者删除等有点(但是访问速度较数组慢)。
数据链表常有两个域 数据域 与 指针域
内核链标是一个双向循环链表,但是它与我们常用的链表有所不同.
常用的双向链标定义如下:
- typedef struct NODE{
- char data;
- struct NODE *prev;
- struct NODE *next;
- }NODE;
这里的next 指针指向了下一个链标节点,通过node->data获得链标中的数据, 类似下图(但下图有些不准确)。
内核链表结构定义:
- struct list_head {
- struct list_head *next, *prev;
- };
- struct data_struct{
- struct list_head list;
- char data;
- };
在这里我们可以通过内核链标获取获取整个数据结构,并获得有用数据。
这样的好处是:实现了内核链标的通用性,不需要为每个结构定义一个链表,使用统一的内核链表即可。
那我们怎样使用内核链标呢? 如何通过内核链标得到想要的数据结构呢?
使用内核链表:
定义包含内核链标的数据结构
- struct list_sample{
- struct list_head list;
- /*The data you need to use*/
- char ch;
- int x;
- /*************************/
- };
只要在数据结构中包含struct list_head成员即可。
初始化内核链表
使用内核链标需要一个链表头,故需要先行初始化脸表头
- static inline void INIT_LIST_HEAD(struct list_head *list)
添加一个链表节点
- static inline void list_add(struct list_head *new, struct list_head *head)
- {
- __list_add(new, head, head->next);
- }
- static inline void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
- {
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
- }
它会将新的节点放于prev 与 next之间。
同样可以调用list_add_tail, 在head之前添加一个链表节点。
删除链表节点:
- static inline void __list_del_entry(struct list_head *entry)
- {
- __list_del(entry->prev, entry->next);
- }
- static inline void __list_del(struct list_head * prev, struct list_head * next)
- {
- next->prev = prev;
- prev->next = next;
- }
这里即将 entry节点从链表中删除(其实节点仍存在只是不在链表里边了)
- static inline void list_del(struct list_head *entry)
获取数据结构
- #define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
定义 list_entry宏 来获取数据结构,它会调用container_of 宏来获取这个结构体(container_of 宏我在前边的文章里边已经阐述过)
ptr 填入链表节点指针, type填入数据结构体类型, member示意链标在结构体中的名字。
如果现在我们知道链表的指针为entry,就可以这样获取整个结构体。
- struct list_sample sample = list_entry(entry, struct list_sample, list);
以上是最基本的使用方法。