科研日志-字符设备驱动

    我的第一个字符驱动刚刚写好,摸摸还是热的~n_n 先做个总结吧,免得忘了!

    编写一个字符设备驱动大概分为三个部分:

    1.驱动程序本身,一个.c文件

    2.Makefile文件

    3.测试程序

 

  一.字符驱动

 

     以下是程序的清单,这个驱动的功能非常简单,先将保存的数据打印出来,然后提示用户输入,讲输入的信息保存到内核态,下面通过代码那的注释以说明

 

 

/*在这个程序的末尾有两个函数 module_init(GlobalChar_init);

  module_exit(GlobalChar_exit);

      同C程序不同,驱动程序不是从main()开始的,而是通过两个宏告诉系统程序的入口,即GlobalChar_init这个函数,下面那个是退出的函数,程序初始化的时候会自动调用GlobalChar_init

*/

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <asm/uaccess.h>

 

MODULE_LICENSE("GPL");//

MODULE_AUTHOR("LIU");//作者姓名

 

#define DEV_NAME "GlobalChar"//设备名称

 

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

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

 

static int char_major =0;

static int GlobalData =0;

 

//初始化字符驱动的file_operation结构

struct file_operations globalchar_fops =

{

.read =GlobalRead,

.write =GlobalWrite

};//定义的设备结构,返回两个程序指针

 

//模块初始化

static int __init GlobalChar_init(void)

{

int ret;

ret = register_chrdev(char_major,DEV_NAME,&globalchar_fops);//注册设别驱动

//这是操作系统提供的一个API,通过这个函数来注册一个字符型的设备,参数是 (主设备号,字符设备名,设备结构)

if(ret<0)

{

//在驱动中没有stdio的头文件,所以用不了printf()

printk(KERN_ALERT "GlobalChar REG FAIL!/n");

}

else

{

printk(KERN_ALERT "GlobalChar REG Success!/n");

char_major=ret;

printk(KERN_ALERT "MAJOR = %d/n",char_major);

}

return ret;

}

 

//模块卸载函数

static void __exit GlobalChar_exit(void)

{

unregister_chrdev(char_major,DEV_NAME);//注销设备

return;

}

 

//设备驱动read函数

static ssize_t GlobalRead(struct file *filp,char *buf,size_t len,loff_t *off)//注意这个函数的格式,都是系统定义的

{

if(copy_to_user(buf,&GlobalData,sizeof(int)))//从内核复制GlobalData到用户空间,因为这个程序是运行在内核态的,所以调到用户态的话,要中这个函数

{

return -EFAULT;

}

return sizeof(int);

}

 

//驱动设备writt函数

static ssize_t GlobalWrite(struct file *filp,const char *buf,size_t len,loff_t *off)

{

if(copy_from_user(&GlobalData,buf,sizeof(int)))

{

return -EFAULT;

}

return sizeof(int);

}

 

module_init(GlobalChar_init);

module_exit(GlobalChar_exit);

 

//

 

二、Makefile的编写

 

      首先Makefile文件需要和上面编写的驱动放在一个文件夹里面,当执行make命令的时候系统会自动寻找文件夹下面的Makefile文件然后执行,Makefile文件有一定的语法和格式,这部分具体我没有研究,先把代码贴上:

 

 

ifneq ($(KERNELRELEASE),)

 

obj-m:=GlobalCharDev.o

 

else

KERNELDIR=/lib/modules/$(shell uname -r)/build

 

PWD:=$(shell pwd)

 

default:

 

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

 

clean:

 

rm -rf *.o *.mod.c *.mod.o *.ko

endif

 

 

########################################################

 

OK !Makefile文件写好了,然后在命令提示符下面输入make,出现如下提示:

 

1.make文件

 

 

dickens@ubuntu:~/example$ make

make -C /lib/modules/2.6.35-22-generic/build M=/home/dickens/example modules

make[1]: 正在进入目录 `/usr/src/linux-headers-2.6.35-22-generic'

  CC [M]  /home/dickens/example/GlobalCharDev.o

  Building modules, stage 2.

  MODPOST 1 modules

  LD [M]  /home/dickens/example/GlobalCharDev.ko

make[1]:正在离开目录 `/usr/src/linux-headers-2.6.35-22-generic'

 

dickens@ubuntu:~/example$ ls
GlobalCharDev.c   GlobalCharDev.mod.c  GlobalCharDev.o  modules.order   test
GlobalCharDev.ko  GlobalCharDev.mod.o  Makefile         Module.symvers  test.c
2.加载驱动
这是我们看到example文件下面编译出了很多文件,其中GlobalCharDev.ko 就是驱动模块文件了,下面我们要做的就是加载驱动,加载驱动的时候需要管理员权限,操作如下:
dickens@ubuntu:~/example$ sudo insmod GlobalCharDev.ko
这样我们就加载了这个驱动,输入lsmod命令可以查看当前被加载的驱动
3.创建节点
      linux的设备都是以文件的形式存在的,每一个文件在/dev下面都会有一个节点,要想调用刚才写的驱动还必须在/dev下面创建一个文件设备节点,同时当驱动被加载的时候会系统会为他分配一个主设备号和此设备号,在创建节点的时候一定要正确填写主设备号,否则驱动无法正确调用。具体操作如下:
输入cat /proc/devices 回车
      就可以看到当前被加载的设备的设备号,我的设备在这里,250 GlobalChar,即主设备号为250,下面创建设备节点:
dickens@ubuntu:~/example$ cd /dev
dickens@ubuntu:/dev$ sudo mknod -m 666 /dev/GlobalChar c 250 0
这句话的意思是这样的,创建节点 权限为可读写,设备名为GlobalChar ,后面的c 表示他是字符设备,250是主设备号(我们由上面得到的),0表示自动分配此设备号。
dickens@ubuntu:/dev$ ls -l GlobalChar 
crw-rw-rw- 1 root root 250, 0 2011-03-24 21:23 GlobalChar
*****这样一个设备就加载好了,下面要写一个应用程序来测试他
三、写应用程序
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#define DEV_NAME "/dev/GlobalChar"
int main()
{
int fd,num;
//打开设备文件
fd=open(DEV_NAME,O_RDWR,S_IRUSR| S_IWUSR);
if(fd<0)
{
printf("Open Device Fail!/n");
return -1;
}
        //读取当前设备数值
else
{
printf("OPEND!/n");
}
read(fd,&num,sizeof(int));
printf("The GlobalChar is %d/n",num);
printf("Please input a number wrrten to GlobalChar!/n");
scanf("%d",&num);
write(fd,&num,sizeof(int));
read(fd,&num,sizeof(int));
printf("The number of GlobalChar is %d/n",num);
close(fd);
return 0;
}
这个程序非常的简单,就不做介绍了,需要注意的是,因为在linux是以文件的形式存在的,所以对设备的操作和对文件操作类似,用Open、Read、Write 操作,编译看看:
dickens@ubuntu:~/example$ gcc -o test test.c
执行结果:
dickens@ubuntu:~/example$ ./test
OPEND!
The GlobalChar is 0
Please input a number wrrten to GlobalChar!
123
The number of GlobalChar is 123
这就是一个字符设备驱动编写的全过程,需要注意的是设备号得问题,之前在写的时候没有办法正常运行,问题就是在创建节点的时候设备号给的不对!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值