现在的位置: 首页 > 综合 > 正文

我对字符设备驱动的理解

2013年07月19日 ⁄ 综合 ⁄ 共 3405字 ⁄ 字号 评论关闭

 

实验要求:编写简单的字符设备驱动模块,能够支持建立和删除节点,节点进行读写操作时分别打印“You are reading!”和“You are writing!”。

 

思想整理:

1.     本实验需要我们编写一个驱动程序,mymodule.c

2.     该驱动程序经编译后生成.ko文件,使用Makefile文件生成mymodule.ko

3.     可以挂在到系统上 insmod mymodule.ko

4.     然后通过其主设备号将其生成一个节点 mknod mymodule0 c 249 0

5.     mumodule0进行读写操作  cat mymodule0   ls > mymodule

 

实验原理:

1.     mymodule.c的组成

(1)       my_init_module()函数

当使用insmod命令时,系统会调用程序的module_init()函数,这样也就调用了我们写的my_init_module()函数。

而我们应当在my_init_module()中完成的操作有以下这些:

注册设备,注册的目的是注册了自己写的这些file operations,如readwrite等,而不是用原来VFSreadwrite函数同时以后可以使用主设备号来使用该模块。

注册的语句是:

Major = register_chrdev(0,chardev,&my_fops),解释一下参数

第一个0表示让系统帮我分配主设备号,你也可以自己写,但是这样你还得查一下系统中有空的主设备号。

第二个参数是说明这是一个字符设备驱动,不用改

第三个就是我们用file_operations定义的文件操作结构体的引用

获取主设备号,输出一下主设备号,这样你在mknod的时候就可以找到这个设备了。

 

(2)       my_cleanup_module()函数

另一个必须有的函数是module_exit,这个函数在我们rmmod时会被调用,而这个函数又同时调用了我们自己写的函数,所以如果我们在my_cleanup
module
函数中写printk(goodbye),那么在用rmmod时他就输出了。

my_cleanup_module我们还有一个必要的事要做,把刚刚注册的设备给注销掉,命令是unregister_chrdev(Major,chardev);

 

(3)       struct file_operations my_fops{};结构体

定义了这个结构体后,这个file operations就会替换原来虚拟文件系统的file operations,具体的方法很简单,仿照例子即可,唯一需要注意的是顺序必须按照原本file operations的顺序。

struct file_operations my_fops={

.open=my_open,

.release=my_release

};


(4)      根据你要重定义的操作,也就是在file
operations
结构体里面写的那几个,相应的写他们的函数。

 

tips:在设备打开时,会用到一个try_module_get函数,这个函数的目的是让系统知道这个模块又被用了一次,只有系统确实知道我们的模块被用了多少次,模块在注销时才不会出错,同理,用module_put函数,可以跟系统说,我的某一次调用已经结束了!!

 

2Makefile的编写,由于这个实验编译的是模块,所以需要用到内核里的Makefile文件,具体怎么编译的还没有弄清楚,但是Makefile的代码是这样的

 
 

KERNELDIR :=
/lib/modules/`uname -r`/build

obj-m :=
mymodule.o

module:

       make -C $(KERNELDIR) M=`pwd` modules

clean:

       rm -fr mymodule.o mymodule.ko mymodule.mod.*

 

 

 

 

 

 

 

 

 

 

代码:

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

 

/*函数声明*/

int my_init_module(void);

void my_cleanup_module(void);

static int my_open(struct inode *, struct
file *);

static int my_release(struct inode *, struct
file *);

static ssize_t my_read(struct file
*, char *, size_t, loff_t *);

static ssize_t my_write(struct file
*, const char
*, size_t, loff_t *);

      

#define SUCCESS 0

#define DEVICE_NAME "chardev"

#define BUF_LEN 80

 

static int Major;

static int Device_Open = 0;

 

struct file_operations my_fops={

       .read=my_read,

       .write=my_write,

       .open=my_open,

       .release=my_release

};

 

int my_init_module(void){  /*init module*/

       printk("Hello! It is from mymodule /n");

       Major
= register_chrdev(0,DEVICE_NAME,&my_fops);

       if(Major){

              printk("major is %d /n",Major);

       }

       else{

              printk("Registeration failed! /n");

       }

       return 0;

}

void my_cleanup_module(void){

       unregister_chrdev(Major,DEVICE_NAME);

       printk("mymodule says Good Bye to you!/n");

}

 

static int my_open(struct inode *inode,struct
file *file){

/*The device can be
used by more than one

process*/

/*Everytime one
process open the device*/

/*this device will
call the try_module_get function */

/*to increase the
use count*/

       if(Device_Open)

              return -EBUSY;

       Device_Open++;

       try_module_get(THIS_MODULE);

       return SUCCESS;

}

 

static int my_release(struct inode *inode,struct
file *file){

       Device_Open--;

       module_put(THIS_MODULE);  //decreasing use
count differs to increasing

       return 0;

}

 

static ssize_t my_read(struct file
*flip,char *buffer,size_t length,loff_t
*offset){

       printk("You are reading!");

       return 0;

}

 

static ssize_t my_write(struct file
*flip,const char
*buff,size_t len,loff_t *off){

       printk("You are writing!");

       return -EINVAL;

}

 

MODULE_LICENSE("GPL");

module_init(my_init_module);

module_exit(my_cleanup_module);

 

抱歉!评论已关闭.