Linux 2.6字符设备驱动实例

本文发布时间: 2019-Mar-22
这个程序很简单,但是对初学者把握2.6版内核的字符驱动的脉络应该有一定的帮助。#globalvar.c#include <linux/module.h> //模块所需的大量符号和函数定义#include <linux/init.h> //指定初始化和清楚函数#include <linux/fs.h> //文件系统相关的函数和头文件#include <linux/cdev.h> //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 *);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= //将文件操作与分配的设备号相连{ owner: THIS_MODULE, //指向拥有该模块结构的指针 open: globalvar_open, release: globalvar_release, read: globalvar_read, write: globalvar_write,};struct globalvar_dev //用来表示我们定义设备的结构{ int global_var; //这个变量代表要操作的设备 struct cdev cdev; //内核中表示字符设备的结构};struct globalvar_dev *my_dev; //设备结构的指针static void __exit globalvar_exit(void) //退出模块时的操作{ dev_t devno=MKDEV(dev_major, dev_minor); //dev_t是用来表示设备编号的结构 cdev_del(&my_dev->cdev); //从系统中移除一个字符设备 kfree(my_dev); //释放自定义的设备结构 unregister_chrdev_region(devno, 1); //注销已注册的驱动程序 printk("globalvar unregister success/n");}static int __init globalvar_init(void) //初始化模块的操作{ int ret, err; dev_t devno=MKDEV(dev_major, dev_minor); //动态分配设备号,次设备号已经指定 ret=alloc_chrdev_region(&devno, dev_minor, 1, "globalvar"); //保存动态分配的主设备号 dev_major=MAJOR(devno); //根据期望值分配设备号 //ret=register_chrdev_region(devno, 1, "globalvar"); if(ret<0) { printk("globalvar register failure/n"); globalvar_exit(); //如果注册设备号失败就退出系统 return ret; } else { printk("globalvar register success/n"); } //为设备在内核空间分配空间 my_dev=kmalloc(sizeof(struct globalvar_dev), GFP_KERNEL); if(!my_dev) { ret=-ENOMEM; //如果分配失败返回错误信息 printk("create device failed/n"); } else //如果分配成功就可以完成设备的初始化 { my_dev->global_var=0; //设备变量初始化为0 cdev_init(&my_dev->cdev, &globalvar_fops); //初始化设备中的cdev结构 my_dev->cdev.owner=THIS_MODULE; //初始化cdev中的所有者字段 //my_dev->cdev.ops=&globalvar_fops; err=cdev_add(&my_dev->cdev, devno, 1); //向内核添加这个cdev结构的信息 if(err<0) printk("add device failure/n"); //如果添加失败打印错误消息 } return ret;}//打开设备文件系统调用对应的操作int globalvar_open(struct inode *inode, struct file *filp){ 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 *filp, const char *buf, size_t len, 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); //返回写数据的大小}module_init(globalvar_init); //模块被装载时调用globalvar_initmodule_exit(globalvar_exit); //模块被卸载时调用globalvar_exit按如下内容编写一个Makefile文件,然后输入make就可以开始自动编译了。编译之后得到了一个名为globalvar.ko的模块文件,这就是我们需要的设备驱动文件。#Makefileifneq ($(KERNELRELEASE), ) obj-m := globalvar.oelse KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd)all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean: $(MAKE) -C $(KERNELDIR) M=$(PWD) cleanendif接下来运行如下代码,将驱动加入内核。insmod globalvar.ko此时可以用dmesg或lsmod命令检查一下模块加载是否成功。如果没有问题,就可以使用mknod构造一个设备文件:mknod /dev/globalvar c 主设备号 0最后,按照下面内容编写一个简单的测试文件并用gcc编译。#test.c#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <fcntl.h>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); 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); close(fd); //关闭设备文件 } else { printf("Device open failure/n"); }}


(以上内容不代表本站观点。)
---------------------------------
本网站以及域名有仲裁协议。
本網站以及域名有仲裁協議。

2020-Jul-13 01:15am
栏目列表