Linux驱动开发cdev驱动分层设计


#ifndef MYDEV_H
#define MYDEV_H #define DYNAMIC_MINOR 256 struct mydev{
const char *name;
const struct file_operations *fops; int minor;
//private 设备文件 和互斥锁
struct device *thisdev;
struct mutex lock;
}; extern int add_mydev(struct mydev *);
extern int del_mydev(struct mydev *); #endif
mydev.h
/*
* 分层分工设计演示
* cdev为接口层
* write by panzhh
*/ #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h> #include "../include/mydev.h" //用来存放设备文件目录指针
static struct class *mydevclass = NULL; //最多为64个字符设备的数组
#define MYDEVMAX 64
static struct mydev *mydevarr[MYDEVMAX]; //存放主设备号
static int mydev_major = ;
//设备名
static const char mydevname[] = "mydev"; //静态分配字符设备对象
static struct cdev cdev; //自己定义的字符设备匹配方法(通过次设备号)
static struct mydev *find_mydev(int minor); //open方法
static int mydev_open(struct inode *inode, struct file *filp)
{
int err = ; //定义两个操作方法集指针用于保存新旧操作方法,
const struct file_operations *old_f, *new_f = NULL; struct mydev *mydev = NULL; int minor = iminor(inode);
printk(KERN_INFO "[%d]mydev_open\n", minor); //匹配字符设备
mydev = find_mydev(minor);
if(NULL == mydev){
printk(KERN_ERR "find_mydev ERR.\n");
return -ENXIO;
} err = ;
new_f = fops_get(mydev->fops);
old_f = filp->f_op;
filp->f_op = new_f;
if (filp->f_op->open) {
filp->private_data = mydev;
err=filp->f_op->open(inode,filp);
if (err) {
fops_put(filp->f_op);
filp->f_op = fops_get(old_f);
}
}
fops_put(old_f); return err;
} static struct file_operations mydevfops = {
.owner = THIS_MODULE,
.open = mydev_open,
}; ///////////////////////////////////////////////////////////////////////////////////通用字符设备 init 框架
alloc_chrdev_region 分配设备号 static int __init mydev_init(void)
{
int ret;
dev_t dev; ret = alloc_chrdev_region(&dev, , MYDEVMAX, mydevname);
if (ret < ) {
printk(KERN_ERR "alloc_chrdev_region error.\n");
return ret;
}
mydev_major = MAJOR(dev); cdev_init(&cdev, &mydevfops);
ret = cdev_add(&cdev, dev, MYDEVMAX);
if (ret) {
printk(KERN_ERR "Error %d adding %s", ret, mydevname);
goto ERR_STEP_0;
} //sys/class/xxx
mydevclass = class_create(THIS_MODULE, mydevname);
if (IS_ERR(mydevclass)) {
printk(KERN_ERR "Unable create sysfs class for demo\n");
ret = PTR_ERR(mydevclass);
goto ERR_STEP_1;
} //初始化cdev对象指针数组为空,具体的对象在设备加载时得到 struct mydev
for(ret = ; ret < MYDEVMAX; ret++){
mydevarr[ret] = NULL;
} printk(KERN_INFO "mydev_init done.\n"); return ; ERR_STEP_1:
cdev_del(&cdev); ERR_STEP_0:
unregister_chrdev_region(dev, MYDEVMAX); return ret;
} static void __exit mydev_exit(void)
{
dev_t dev;
dev = MKDEV(mydev_major, ); cdev_del(&cdev);
unregister_chrdev_region(dev, MYDEVMAX); class_destroy(mydevclass); printk(KERN_INFO "mydev_exit done.\n");
} module_init(mydev_init);
module_exit(mydev_exit); //////////////////////////////////////////////////////////////////// static struct mydev *find_mydev(int minor)
{
if(minor >= MYDEVMAX){
printk(KERN_ERR "a invalid minor.\n");
return NULL;
} return mydevarr[minor];
} int add_mydev(struct mydev *obj)
{
int i; //先判断次设备号是否为自动分配(这里定义255位自动分配)
if(DYNAMIC_MINOR == obj->minor){
//遍历找到最小未用的次设备号
for(i = ; i < MYDEVMAX; i++){
if(NULL == mydevarr[i])
break;
} //若设备已满返回错误(这里定义64个设备时就不能再添加了)
if(MYDEVMAX == i){
printk(KERN_ERR "[add_mydev]: Cann't alloc minor.\n");
return -EBUSY;
}
//保存分配到的次设备号
obj->minor = i;
} else { //指定的设备号已被用,返回错误
if(NULL != find_mydev(obj->minor)){
printk(KERN_ERR "[add_mydev]: a invalid minor.\n");
return -EINVAL;
}
} //sys/class/xxx/xxx0/dev 创建一个对应设备文件 父目录class指针 父对象 设备号 设备私有数据 设备名
obj->thisdev = device_create(mydevclass, \
NULL, \
MKDEV(mydev_major, obj->minor), \
obj, \
"%s%d", obj->name, obj->minor);
if (IS_ERR(obj->thisdev)) {
return PTR_ERR(obj->thisdev);
} mydevarr[obj->minor] = obj;
printk(KERN_INFO "[add_mydev]: major=%d, minor=%d\n", mydev_major, obj->minor); return ;
} int del_mydev(struct mydev *obj)
{
if(NULL == find_mydev(obj->minor)){
printk(KERN_ERR "[del_mydev]: a invalid minor.\n");
return -EINVAL;
} mydevarr[obj->minor] = NULL; //销毁设备文件
device_destroy(mydevclass, MKDEV(mydev_major, obj->minor));
printk(KERN_INFO "[del_mydev]: major=%d, minor=%d\n", mydev_major, obj->minor); return ;
} EXPORT_SYMBOL(add_mydev);
EXPORT_SYMBOL(del_mydev); MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR ("panzhh");
MODULE_DESCRIPTION ("Driver for mydev");
MODULE_SUPPORTED_DEVICE ("mydev");
mydev.c
ifneq ($(KERNELRELEASE),)
obj-m := mydev.o
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
cp -a Module.symvers $(TOPDIR)/device
mv *.ko $(TOPDIR)/modules/
endif clean:
rm -rf *.o *.symvers *.order *.ko *.mod.c *.markers .tmp_versions .*.cmd
mydev.c_Makefile
ifneq ($(KERNELRELEASE),)
obj-m := demoa.o
obj-m += demob.o
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
mv *.ko $(TOPDIR)/modules/
endif clean:
rm -rf *.o *.symvers *.order *.ko *.mod.c *.markers .tmp_versions .*.cmd
demo.c_Makefile
/*
* 自定义设备框架
* write by panzhh
* 设备具体驱动
*/ #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/types.h> #include "../include/mydev.h" static int minor = ; //设备的具体操作方法(驱动)
static int demo_open(struct inode *inode, struct file *filep)
{
minor = iminor(inode); printk(KERN_INFO "[%d]demo_open, inode=%p\n", minor, inode);
return ;
} static int demo_release(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "[%d]demo_release\n", minor);
return ;
} static ssize_t demo_read(struct file *filep, char __user *buf, size_t count, loff_t *fpos)
{
printk(KERN_INFO "[%d]demo_read, inode=%p\n", minor, filep->f_path.dentry->d_inode);
return ;
} static ssize_t demo_write(struct file *filep, const char __user *buf, size_t count, loff_t *fpos)
{
printk(KERN_INFO "[%d]demo_write, inode=%p\n", minor, filep->f_path.dentry->d_inode);
return ;
} static struct file_operations fops = {
.owner = THIS_MODULE,
.read = demo_read,
.write = demo_write,
.open = demo_open,
.release = demo_release,
}; //每个设备的mydev空间在此次分配,并在 init 函数中交由 add_mydev() 进行处理
struct mydev mydev = {
.minor = DYNAMIC_MINOR,
.name = "demo",
.fops = &fops,
}; static int __init demo_init(void)
{
printk(KERN_INFO "demo_init.\n");
return add_mydev(&mydev);
} static void __exit demo_exit(void)
{
del_mydev(&mydev);
printk(KERN_INFO "demob_exit done.\n");
} MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR ("panzhh");
MODULE_DESCRIPTION ("Driver for demo");
MODULE_SUPPORTED_DEVICE ("demo"); module_init(demo_init);
module_exit(demo_exit);
devicedemo.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h> int demofunc(char *devname)
{
int fd = open(devname, O_RDWR);
if( > fd){
perror("open");
return -;
}
printf("open done. fd=%d\n", fd); #define MAX 64
char buf[MAX]={};
int ret = write(fd, buf, MAX);
if( > ret){
perror("write");
}
printf("write done. fd=%d, ret=%d\n", fd, ret);
ret = read(fd, buf, MAX);
if( > ret){
perror("read");
}
printf("read done. fd=%d, ret=%d\n", fd, ret);
getchar(); close(fd);
printf("close done.\n");
return ;
} int main()
{
demofunc("/dev/demo0");
demofunc("/dev/demo1");
}
test.c
CC = gcc
CFLAGS = -Wall -O2 -g -std=gnu99
LDFLAGS = APP = app
OBJS = $(patsubst %.c, %.o, $(wildcard *.c)) $(APP) : $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS) clean:
rm -f $(OBJS) $(APP) *.o
test.c _Makefile
Linux驱动开发cdev驱动分层设计的更多相关文章
- (55)Linux驱动开发之一驱动概述
驱动 ...
- windows 驱动开发入门——驱动中的数据结构
最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...
- linux设备驱动的分层设计思想--input子系统及RTC
转自:linux设备驱动的分层设计思想 宋宝华 http://blog.csdn.net/21cnbao/article/details/5615493 1.1 设备驱动核心层和例化 在面向对象的程序 ...
- 《Linux设备驱动开发具体解释(第3版)》进展同步更新
本博实时更新<Linux设备驱动开发具体解释(第3版)>的最新进展. 2015.2.26 差点儿完毕初稿. 本书已经rebase到开发中的Linux 4.0内核,案例多数基于多核CORTE ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- 2019.05.08 《Linux驱动开发入门与实战》
第六章:字符设备 申请设备号---注册设备 1.字符设备的框架: 2.结构体,struct cdev: 3.字符设备的组成: 4.例子: 5.申请和释放设备号: 设备号和设备节点是什么关系.? 设备驱 ...
- (57)Linux驱动开发之三Linux字符设备驱动
1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...
- Linux驱动开发概述
原文出处:http://www.cnblogs.com/jacklu/p/4722563.html Linux设备分类 设备的驱动程序也要像裸机程序那样进行一些硬件操作,不同的是驱动程序需要" ...
- 驱动开发学习笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇
驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇下面这段摘自 linux源码里面的文档 : Documentatio ...
随机推荐
- ASP.NET 开发学习视频教程大全(共800集)
ASP.NET是微软.NET平台的支柱之一,被广泛应用在WEB等互联网开发领域,因此它的强大性和适应性,可以使它运行在Web应用软件开发者的几乎全部的平台上.这里整理了最全的ASP.NET开发学习 ...
- Java基础--多线程的方方面面
1,什么是线程?线程和进程的区别是什么? 2,什么是多线程?为什么设计多线程? 3,Java种多线程的实现方式是什么?有什么区别? 4,线程的状态控制有哪些方法? 5,线程安全.死锁和生产者--消费者 ...
- thinkphp 邮件发送
最近项目上要求,要做个邮件发送的功能,因为用到的框架是ThinkPHP,于是就自己整理一下. 引入class.phpmailer.php,大家可以去这个链接去下载: http://pan.baidu. ...
- 想追赶.Net的脚步?Java面前障碍重重
待到Java 8面世之时 .Net的进度时钟恐怕已经又走过了两到五年——届时微软做出的调整将使二者差距进一步拉大. 就在几周之前,我详细介绍了Java 8中值得期待的几大主要功能.不过当时我并没有提到 ...
- mysql中explain优化分析
效率比较 range >index > all
- HTml <meta>标签的使用(重要)
<meta> 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词. 1.设置网页字符编码 <meta http-equiv=&q ...
- Delphi-Delete 过程
过程名称 Delete 所在单元 System 过程原型 procedure Delete ( var Source : string; StartChar : Integer; Count : In ...
- python运维开发之第七天
一.面向对象编程进阶 1.静态方法 @staticmethod 名义上归类管理,实际上跟类没什么关系 在静态方法里,访问不了类或实例中的任何属性 class Static_method(object) ...
- python学习第十六天 --继承进阶篇
这一章节主要讲解面向对象高级编程->继承进阶篇,包括类多继承介绍和继承经典类和新式类属性的查找顺序不同之处. 多继承 上一章节我们讲到继承,子类继承父类,可以拥有父类的属性和方法,也可以进行扩展 ...
- uva 10382 - Watering Grass(区域覆盖问题)
Sample Input 8 20 2 5 3 4 1 1 2 7 2 10 2 13 3 16 2 19 4 3 10 1 3 5 9 3 6 1 3 10 1 5 3 1 1 9 1 Sample ...