#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驱动分层设计的更多相关文章

  1. (55)Linux驱动开发之一驱动概述

                                                                                                      驱动 ...

  2. windows 驱动开发入门——驱动中的数据结构

    最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...

  3. linux设备驱动的分层设计思想--input子系统及RTC

    转自:linux设备驱动的分层设计思想 宋宝华 http://blog.csdn.net/21cnbao/article/details/5615493 1.1 设备驱动核心层和例化 在面向对象的程序 ...

  4. 《Linux设备驱动开发具体解释(第3版)》进展同步更新

    本博实时更新<Linux设备驱动开发具体解释(第3版)>的最新进展. 2015.2.26 差点儿完毕初稿. 本书已经rebase到开发中的Linux 4.0内核,案例多数基于多核CORTE ...

  5. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  6. 2019.05.08 《Linux驱动开发入门与实战》

    第六章:字符设备 申请设备号---注册设备 1.字符设备的框架: 2.结构体,struct cdev: 3.字符设备的组成: 4.例子: 5.申请和释放设备号: 设备号和设备节点是什么关系.? 设备驱 ...

  7. (57)Linux驱动开发之三Linux字符设备驱动

    1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...

  8. Linux驱动开发概述

    原文出处:http://www.cnblogs.com/jacklu/p/4722563.html Linux设备分类 设备的驱动程序也要像裸机程序那样进行一些硬件操作,不同的是驱动程序需要" ...

  9. 驱动开发学习笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇

    驱动开发读书笔记. 0.04  linux 2.6 platform device register 平台设备注册  1/2 共2篇下面这段摘自 linux源码里面的文档 : Documentatio ...

随机推荐

  1. cas sso单点登录系列2:cas客户端和cas服务端交互原理动画图解,cas协议终极分析

    转:http://blog.csdn.net/ae6623/article/details/8848107 1)PPT流程图:ppt下载:http://pan.baidu.com/s/1o7KIlom ...

  2. Testlink接口使用方法-python语言远程调用

    deepin@deepin-pc:~/test$ cat libclienttestlink.py #!/usr/bin/env python3 # -*- coding: utf-8 -*- #! ...

  3. python中的formatter的详细用法

    今天抽空学习了一下python中的string service中的formatter的相关用法,主要是为了让自己的代码看起来更加和谐,因为很多java或者c语言过来的开发者都不怎么爱使用python的 ...

  4. django 内建标签和过滤器参考

    下面的标签和过滤器参考就是为那些没有 admin 站点的可用的人准备的.由于 Django 是高度可定制的,你的 admin 里的关于标签和过滤器的参考可以认为是最可信的. 内建标签参考 block ...

  5. python中read、readline和readlines的区别

    read        读取整个文件 readline    读取下一行 readlines   读取整个文件到一个迭代器以供我们遍历(读取到一个list中,以供使用,比较方便). 123.txt内容 ...

  6. solr拼写检查配置

    拼写检查功能,能在搜索时,提供一个较好用户体验,所以,主流的搜索引擎都有这个功能. 那么什么是拼写检查,其实很好理解,就是你输入的搜索词,可能是你输错了,也有可能在它的检索库里面根本不存在这个词,但是 ...

  7. 温故而知新 C++基本类型

    C++基本类型大小: 在32位计算机中测试得到:sizeof(bool) == 1sizeof(char) == 1 sizeof(short) == 2sizeof(int) == 4sizeof( ...

  8. C++访问权限【原创】

    可以访问private的有:1.本类的函数:2.友元函数.   可以访问protected的有:1.本类的函数:2.子类函数:3.友元函数.   可以访问public的有:1.本类的函数和对象:2.子 ...

  9. 用C#实现网络爬虫(一)

    网络爬虫在信息检索与处理中有很大的作用,是收集网络信息的重要工具. 接下来就介绍一下爬虫的简单实现. 爬虫的工作流程如下 爬虫自指定的URL地址开始下载网络资源,直到该地址和所有子地址的指定资源都下载 ...

  10. What qualities characterize a great PhD student

    省理工计算机教授David Karger接触了许多世界上最杰出的博士生,近日总结出了优秀博士通常具备的五点品质:0 过人的智力 1 好奇心 2 创造力 3 纪律性与生产力 4 与观众沟通 5 与伙伴沟 ...