Linux 字符设备驱动实例
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
if(ret<0)
{
printk("globalvar register failure\n");
globalvar_exit();
//如果注册设备号失败就退出
系统 return ret;
} else {
printk("globalvar register success\n"); }
//为设备在内核空间分配空间
{
my_dev->global_var=0; 0
//设备变量初始化为
cdev_init(&my_dev->cdev, &globalvar_fops); ev 结构
Hale Waihona Puke Baidu
//初始化设备中的 cd
my_dev->cdev.owner=THIS_MODULE; 所有者字段
//初始化 cdev 中的
err=cdev_add(&my_dev->cdev, devno, 1); ev 结构的信息
Linux 字符设备驱动实例 1
看了《Linux 设备驱动程序》的前几章,我结合这篇教程中给出的一个 2.4 版内核的字符驱动, 自己编写了一个 2.6 版内核的驱动程序,并且加上了详细的注释。这个程序很简单,但是对初 学者把握 2.6 版内核的字符驱动的脉络应该有一定的帮助,也可以算作我对《Linux 设备驱动 程序》前几章学习的一个小结。
}
module_init(globalvar_init); module_exit(globalvar_exit);
//模块被装载时调用 globalvar_init //模块被卸载时调用 globalvar_exit
//按如下内容编写一个 Makefile 文件,然后输入 make 就可以开始自动编译了。编译之后得 到了一个名为 globalvar.ko 的模块文件,这就是我们需要的设备驱动文件。
//注销已注册的驱动程序
printk("globalvar unregister success\n"); }
static int __init globalvar_init(void)
//初始化模块的操作
{
int ret, err;
dev_t devno=MKDEV(dev_major, dev_minor);
//用来表示我们定义设备的结构
int global_var; struct cdev cdev; };
//这个变量代表要操作的设备 //内核中表示字符设备的结构
struct globalvar_dev *my_dev;
//设备结构的指针
static void __exit globalvar_exit(void)
//动态分配设备号,次设备号已经指定
ret=alloc_chrdev_region(&devno, dev_minor, 1, "globalvar");
//保存动态分配的主设备号
dev_major=MAJOR(devno);
//根据期望值分配设备号
//ret=register_chrdev_region(devno, 1, "globalvar");
//向内核添加这个 cd
if(err<0)
错误消息
printk("add device failure\n");
//如果添加失败打印
}
return ret;
}
//打开设备文件系统调用对应的操作
int globalvar_open(struct inode *inode, struct file *filp) {
//再次读取
文件
close(fd);
}
else
{
printf("Device open failure\n");
//关闭设备
} }
main()
{
int fd, num;
fd=open("/dev/globalvar", O_RDWR, S_IRUSR|S_IWUSR); 式打开设备文件
//可读写方
if(fd!=-1)
{
变量
read(fd, &num, sizeof(int));
printf("The globalvar is %d\n", num);
//cdev 结构的头文件
#include <asm/uaccess.h> //在内核和用户空间中移动数据的函数
MODULE_LICENSE("GPL");
//指定代码使用的许可证
//文件操作函数的声明 int globalvar_open(struct inode *, struct file *); int globalvar_release(struct inode *, struct file *); ssize_t globalvar_read(struct file *, char *, size_t, loff_t *);
//#globalvar.c
#include <linux/module.h> //模块所需的大量符号和函数定义
#include <linux/init.h>
//指定初始化和清楚函数
#include <linux/fs.h>
//文件系统相关的函数和头文件
#include <linux/cdev.h>
接下来运行如下代码,将驱动加入内核。 insmod globalvar.ko 此时可以用 dmesg 或 lsmod 命令检查一下模块加载是否成功。如果没有问题,就可以使用 mk nod 构造一个设备文件:
mknod /dev/globalvar c
最后,按照下面内容编写一个简单的测试文件并用 gcc 编译。 //#test.c #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <fcntl.h>
//写设备文件系统调用对应的操作 ssize_t globalvar_write(struct file *filp, const char *buf, size_t le n, loff_t *off)
{ //获取指向已分配数据的指针 struct globalvar_dev *dev=filp->private_data; //从用户空间复制数据到内核中的设备变量 if(copy_from_user(&dev->global_var, buf, sizeof(int))) { return -EFAULT; } return sizeof(int); //返回写数据的大小
struct globalvar_dev *dev; //根据 inode 结构的 cdev 字段,获得整个设备结构的指针 dev=container_of(inode->i_cdev, struct globalvar_dev, cdev); //将 file 结构中的 private_data 字段指向已分配的设备结构 filp->private_data=dev; return 0; }
//关闭设备文件系统调用对应的操作 int globalvar_release(struct inode *inode, struct file *filp) {
return 0; }
//读设备文件系统调用对应的操作 ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff _t *off) {
//获取指向已分配数据的指针 struct globalvar_dev *dev=filp->private_data; //将设备变量值复制到用户空间 if(copy_to_user(buf, &dev->global_var, sizeof(int))) {
return -EFAULT; } return sizeof(int); //返回读取数据的大小 }
ssize_t globalvar_write(struct file *, const char *, size_t, loff_ t *);
int dev_major = 50;
//指定主设备号
int dev_minor = 0;
//指定次设备号
struct file_operations globalvar_fops= //将文件操作与分配的设备号相连
//退出模块时的操作
{
dev_t devno=MKDEV(dev_major, dev_minor); 号的结构
//dev_t 是用来表示设备编
cdev_del(&my_dev->cdev); 备
//从系统中移除一个字符设
kfree(my_dev);
//释放自定义的设备结构
unregister_chrdev_region(devno, 1);
//读取设备
printf("Please input the num written to globalvar\n");
scanf("%d", &num);
write(fd, &num, sizeof(int)); 量
//写设备变
read(fd, &num, sizeof(int)); 刚才写的值
printf("The globalvar is %d\n", num);
//#Makefile ifneq ($(KERNELRELEASE), )
obj-m := globalvar.o else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean endif
my_dev=kmalloc(sizeof(struct globalvar_dev), GFP_KERNEL);
if(!my_dev)
{
ret=-ENOMEM;
//如果分配失败返回错误信息
printk("create device failed\n");
}
else
//如果分配成功就可以完成设
备的初始化
{ owner: THIS_MODULE,
//指向拥有该模块结构的指针
open: globalvar_open,
release: globalvar_release,
read: globalvar_read,
write: globalvar_write,
};
struct globalvar_dev {