#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. Hibernate 主键生成策略

    表示符生成器 描述 Increment 由hibernate自动以递增的方式生成表识符,每次增量为1 Identity 由底层数据库生成表识符.条件是数据库支持自动增长数据类型. Sequence H ...

  2. Java中的继承与组合

    本文主要说明Java中继承与组合的概念,以及它们之间的联系与区别.首先文章会给出一小段代码示例,用于展示到底什么是继承.然后演示如何通过“组合”来改进这种继承的设计机制.最后总结这两者的应用场景,即到 ...

  3. apache静态文件配置

    开发环境配置 需要下面几个步骤 1. 在app目录下创建static目录,将静态文件和相关文件夹放到此目录下,如your_app/static/img等 2. 确保settings.py中的INSTA ...

  4. 如何利用PowerPoint2013制作阶梯流程图?

    制作阶梯流程图有哪些窍门呢?下面我们一起来看看吧: ①启动PowerPoint2013,单击菜单栏--插入--形状,选择方角矩形,在图中画出来. ②画好矩形,摆放到合适的位置,如下图所示. ③然后再次 ...

  5. Linux shell (一)

    echo -e "Hello World! \a \n"     # -e 解析反斜杠 read -p "Please input your first name: &q ...

  6. access数据库管理软件收集下载

    access百科 Microsoft Office Access是由微软发布的关系数据库管理系统.它结合了 MicrosoftJet Database Engine 和 图形用户界面两项特点,是 Mi ...

  7. linux c redirect 重定向

    用execvp实现时,运行adb,如果adb 服务没有启动,会启动adb服务,启动adb服务时,pipe返回的管道在读的时候堵塞了. 查看了popen的源码,发现popen是用sh -c来执行的,避免 ...

  8. mongodb 排序 Unable to determine the serialization information for the expression 异常

    好久没用mongodb了...最近又开始用起来了. 遇到情景:   2句话分开写.是正常的,因为我是先取再排序的   然而.我想直接排序出来. 就写在了一起.最后.ToList()   然后报 Una ...

  9. zoj 3777 Problem Arrangement

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5264 题意:给出n道题目以及每一道题目不同时间做的兴趣值,让你求出所有做题顺序 ...

  10. 玩玩SPARK

    没有SCALA的东东,玩不起哈. ./spark-shell 从文件生成一个DRIVER? val logFile = sc.textFile("hdfs://192.168.14.51:9 ...