这几天开始看比较难的 linux设备驱动程序了。
看到本书作者编写的代码,(从官网上下载到的示例:
大家也可以从这里下载。
http://download.csdn.net/detail/zhaole20094463/4541209)
不禁对该书作者科波特敬仰万分。看过之后终于知道为什么这本书比较难了。
我们对书籍评价的难,无非就是两个原因,一个是写法太艰涩,不好理解。
另外一个就是信息量太大。我想这本书难的原因就在于第二点吧。
我们学习程序编写的时候,我想除了看书的时候,最重要的就是看代码。
很不幸的是,这本书的代码也不是那么容易让我们看明白的。
其实,这样不怪作者。而是因为他在编写了该书的示例代码的时候考虑了特别多
的东西,考虑的特别多的情况。比如我们在进行设备注册时候分配设备号,我们可以
在编译时制定,也可以自动获取,也可以在我们加载模块的时候通过参数传递进去。
而该书作者的代码恰恰把这几点都做到了。
所以我试着自己将该作者的代码简化一些,自己编写一个简单的scull函数。
同时加上了详细的注释,希望能给大家一些帮助。
//#include <linux/config.h>
#include<linux/module.h>#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/errno.h>
#include<linux/fcntl.h>
#include<linux/cdev.h>
#include<linux/kdev_t.h>
#include<asm/system.h>
#include<asm/uaccess.h>
#include<linux/slab.h>
#define SCULL_MAJOR 0
#define SCULL_NR_DEVS 1
MODULE_LICENSE("Dual BSD/GPL");
int scull_major = SCULL_MAJOR;
int scull_minor = 0;
int scull_nr_devs = SCULL_NR_DEVS;
int scull_quantum=4000;
int scull_qset =1000;
struct scull_qset {
void **data;
struct scull_qset *next;
};
struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure*/
};//由于我们的驱动程序没有硬件所以我们就自己在电脑的内存里划出一段来作为硬件。这个就是我们声明的硬件的结构体。
struct scull_dev *scull_devices;
static void scull_setup_cdev(struct scull_dev *dev,int index);
static int scull_release(struct inode * inode , struct file * filp);
static int scull_open(struct inode * inode,struct file *filp);
//ssize_t scull_read(struct file *filp;char __user *buff,ssize_t count,loff_t *offp);
ssize_t scull_read(struct file *filp,const char __user *buff,size_t count,loff_t *f_pos);
struct scull_qset *scull_follow(struct scull_dev *dev,int n);
ssize_t scull_write(struct file *filp,const char __user *buff,size_t count,loff_t *f_pos);
int scull_trim(struct scull_dev *dev);
void scull_cleanup_module(void);
struct file_operations scull_fops = //定义控制函数
{
.owner = THIS_MODULE,
.open = scull_open,
.read = scull_read,
.write = scull_write,
.release = scull_release,
};
int scull_trim(struct scull_dev *dev)//清空链表
{
struct scull_qset *next,*dptr;//定义两个结构体指针
int qset = dev->qset; //将scull_dev中qset 取出存储在 qset中
int i;
for(dptr = dev->data ; dptr ; dptr = next)//从第一个链表地址开始遍历,将数据清零,判断下一个链表的地址是不是NULL,
//链表末尾的指针指向NULL,操作条件是将链表的地址依次赋给dptr。
{
if(dptr -> data) //如果链表地址不为空,执行下面操作
{
for(i=0;i<qset;i++) //循环,
kfree(dptr->data[i]);//kfree该链表的数据所占的内存
kfree(dptr->data);//释放链表头数据所占的内存
dptr->data = NULL;//将表头的数据写为NULL
}
next = dptr -> next;//将下一个链表的地址赋给next
kfree(dptr); //释放该地址的内存
}
dev->size = 0 ;//初始化scull_dev结构
dev->quantum = scull_quantum;
dev->qset = scull_qset;
dev->data = NULL;
retu