参考文章http://dev.yesky.com/186/2623186.shtml,本文浅显易懂,写得非常好,看完了再去看《Linux设备驱动》就会更容易理解。
不过文章内有错误,好像作者没有自己运行过似的,将用红色字体指明。
//------------------------------------globalvar.c----------------------------------
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
#define MAJOR_NUM 250 //原文是254,不过我的设备已经占用了
static ssize_t globalvar_read(struct file *,char *,size_t,loff_t *);
static ssize_t globalvar_write(struct file *,const char *,size_t,loff_t *);
struct file_operations globalvar_fops =
{
read:globalvar_read,
write:globalvar_write,
};
static int global_var=0;
static int __init globalvar_init(void)
{
int ret;
ret=register_chrdev(MAJOR_NUM,"globalvar",&globalvar_fops);
if(ret)
{
printk("globalvar register failture");
}
else
{
printk("globalvar register success");
}
return ret;
}
static void __exit globalvar_exit(void)
{
int ret;
unregister_chrdev(MAJOR_NUM,"globalvar");
//错误我已经注释掉了
/*
ret = unregister_chrdev(MAJOR_NUM,"globalvar");
if(ret)
{
printk("globalvar unregister failure");
}
else
{
printk("globalvar unregister success");
}
*/
}
static ssize_t globalvar_read(struct file *filp,char *buf,size_t len,loff_t *off)
{
if(copy_to_user(buf,&global_var,sizeof(int)))
{
return -EFAULT;
}
return sizeof(int);
}
static ssize_t globalvar_write(struct file *filp,const char *buf,size_t len,loff_t *off)
{
if(copy_from_user(&global_var,buf,sizeof(int)))
{
return -EFAULT;
}
return sizeof(int);
}
module_init(globalvar_init);
module_exit(globalvar_exit);
//---------------------------end------------------------------------
使用原文章编译的方法我是没成功,就用我给出的Makefile吧,make一下就行了,记得把hello.o改成globalvar.o
生成驱动程序
make
加载globalvar模块
sudo insmod globalvar.ko
观察一下设备文件,多出一个globalvar
cat /proc/devices
创建设备节点
mknod /dev/globalvar c 250 0
用户程序,这里不写了,看原文。
编译
gcc -o globalvartest globalvartest.c
下面是我执行的结果
king@king-laptop:~/programe/driver/2$ ./globalvartest
Device open failure
king@king-laptop:~/programe/driver/2$ sudo ./globalvartest //用超级用户
The globalvar is 0
Please input the num writen to globalvar
45
The globalvar is 45
king@king-laptop:~/programe/driver/2$ sudo ./globalvartest
The globalvar is 45
Please input the num writen to globalvar
567
The globalvar is 567
king@king-laptop:~/programe/driver/2$ sudo ./globalvartest
The globalvar is 567
Please input the num writen to globalvar
890
The globalvar is 890
king@king-laptop:~/programe/driver/2$
因为不是标准的C,所以没有main函数。为了标记驱动程序的入口点,就定义了一个module_init()函数来确定入口函数,由module_exit()来确定结束函数(清理垃圾)。由于编译程序是顺序编译的,所以module_init(),module_exit()必须在整个程序的结束位置才能保证编译顺利。
用C语言编写的驱动程序的最大不同就是没有入口函数main,代替他的函数是module_init,exit函数则由module_exit代替。
编写程序离不开自定义函数,驱动程序的又一点儿不同就是:如果自定义函数不在内核中注册,是不允许使用的。注册函数就是将自定义函数,内核和设备关联在一起,这样内核就知道该设备可以使用什么样的函数,而且你定义的函数在其他驱动中是无效的。用户程序在使用设备时,并不是显示地调用驱动程序定义的函数,内核函数与驱动函数有了对应关系。
什么是策略?我可以做什么。我可以做很多事情,比如1,2,3,4,5,6,...
什么是方法?我如何去做。我会做那么多的事情,我应该如何安排顺序呢?
驱动程序提供策略
应用程序提供方法
使用驱动的过程,就是注册和使用驱动函数的过程。
static int __init globalvar_init(void)
{
int ret;
//注册设备驱动
ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);
if (ret) //这里的&globalvar_fops和使用信号的程序类似,自己先定义一个处理函数,然后再使用。
{ //但是这里应该是在内核声明了内核函数的一个别名,如果不定义别名,直接使用内核函数原名应该也可以。
//好象不是啊,后面有被声明函数的定义
printk("globalvar register failure");
}
else
{
printk("globalvar register success");
}
return ret;
}