在Linux内核中你很难看到驱动+应用的程序设计方法,而是使用的是Linux分层框架分层分工,标准化接口+标准化功能代码:
interface - 接口层,标准化接口
device - 设备层,实现功能函数
include - 接口层及设备层共用的头文件目录
modules - 编译输出的模块目录
test - 应用程序
接口层在模块初始化函数中就注册了一个字符设备,操作方法集file_operations是一个纯接口集合
file_operations中的每一个接口调用底层设备层功能函数。操作方法集是一个纯虚函数集合在open的时候替换为底层的设备层的功能函数,如果底层没有实现功能函数,则执行接口层的标准代码。

1、interface代码
/** 分层分工设计演示* cdev为接口层* mydev.c*/#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"#define MYDEVMAX 256
static struct mydev *mydevarr[MYDEVMAX];static struct class *mydevclass = NULL;
static const char mydevname[] = "mydev";static int __init mydev_init(void)
{int i;for(i = 0; i < MYDEVMAX; i++){mydevarr[i] = NULL;}mydevclass = class_create(THIS_MODULE, mydevname);if (IS_ERR(mydevclass)) {printk(KERN_ERR "Unable create sysfs class for mydev\n");return PTR_ERR(mydevclass);}printk(KERN_INFO "mydev_init done.\n");return 0;
}static void __exit mydev_exit(void)
{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);static int mydev_open(struct inode *inode, struct file *filp)
{int ret;struct mydev *obj = NULL;int minor = iminor(inode);printk(KERN_INFO "[%d]mydev_open\n", minor);obj = find_mydev(minor);if(NULL == obj){printk(KERN_ERR "find_mydev ERR.\n");return -EINVAL;}if (!try_module_get(obj->fops->owner)){return -ENODEV;}if(obj->fops->my_open){ret = obj->fops->my_open(obj);if(ret){goto ERR_STEP;}return 0;}ret = -ENODEV;ERR_STEP:module_put(obj->fops->owner);return ret;
}static int mydev_release(struct inode *inode, struct file *filp)
{struct mydev *obj = NULL;int minor = iminor(inode);printk(KERN_INFO "[%d]mydev_release\n", minor);obj = find_mydev(minor);if(NULL == obj){printk(KERN_ERR "find_mydev ERR.\n");return -EINVAL;}module_put(obj->fops->owner);if(obj->fops->my_close){return obj->fops->my_close(obj);}return 0;
}static ssize_t mydev_read(struct file *filep, char __user *buf, size_t count, loff_t *fpos)
{struct mydev *obj = NULL;int minor = iminor(filep->f_path.dentry->d_inode);printk(KERN_INFO "[%d]mydev_read\n", minor);obj = find_mydev(minor);if(NULL == obj){printk(KERN_ERR "find_mydev ERR.\n");return -EINVAL;}if(obj->fops->my_read){return obj->fops->my_read(obj, buf, count);}return 0;
}static ssize_t mydev_write(struct file *filep, const char __user *buf, size_t count, loff_t *fpos)
{struct mydev *obj = NULL;int minor = iminor(filep->f_path.dentry->d_inode);printk(KERN_INFO "[%d]mydev_write\n", minor);obj = find_mydev(minor);if(NULL == obj){printk(KERN_ERR "find_mydev ERR.\n");return -EINVAL;}if(obj->fops->my_write){return obj->fops->my_write(obj, buf, count);}return 0;
}static struct file_operations fops = {.owner  = THIS_MODULE,.read    = mydev_read,.write    = mydev_write,.open    = mydev_open,.release= mydev_release,
};static int setup_cdev(struct mydev *obj)
{int ret;dev_t dev;ret = alloc_chrdev_region(&dev, obj->minor, 1, obj->name);if (ret < 0) {printk(KERN_ERR "alloc_chrdev_region error.\n");return ret;}obj->major = MAJOR(dev);obj->cdev = cdev_alloc();if (NULL == obj->cdev) {ret = -ENOMEM;goto ERR_STEP_0;}cdev_init(obj->cdev, &fops);obj->cdev->owner = THIS_MODULE;ret = cdev_add(obj->cdev, dev, 1);if (ret) {printk(KERN_ERR "Error %d adding %s", ret, obj->name);goto ERR_STEP_1;}obj->thisdev = device_create(mydevclass, \NULL, \dev, \obj, \"%s%d", obj->name, obj->minor);if (IS_ERR(obj->thisdev)) {ret = PTR_ERR(obj->thisdev);goto ERR_STEP_1;}printk(KERN_INFO "setup_cdev done.\n");return 0;ERR_STEP_1:cdev_del(obj->cdev);ERR_STEP_0:unregister_chrdev_region(dev, 1);return ret;
}static void unsetup_cdev(const struct mydev *obj)
{dev_t dev;cdev_del(obj->cdev);dev = MKDEV(obj->major, obj->minor);unregister_chrdev_region(dev, 1);device_destroy(mydevclass, dev);printk(KERN_INFO "unsetup_cdev done.\n");
}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;for(i = 0; i < MYDEVMAX; i++){if(NULL == mydevarr[i])break;}if(MYDEVMAX == i){printk(KERN_ERR "[add_mydev]: Cann't alloc minor.\n");return -EBUSY;}obj->minor = i;i = setup_cdev(obj);if(i){return i;}mydevarr[obj->minor] = obj;printk(KERN_INFO "[add_mydev]: name=%s, major=%d, minor=%d\n",\obj->name, obj->major, obj->minor);return 0;
}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;unsetup_cdev(obj);    printk(KERN_INFO "[del_mydev]: name=%s, major=%d, minor=%d\n",\obj->name, obj->major, obj->minor);return 0;
}EXPORT_SYMBOL(add_mydev);
EXPORT_SYMBOL(del_mydev);MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR ("gh");
MODULE_DESCRIPTION ("Driver for mydev");
MODULE_SUPPORTED_DEVICE ("mydev");
2、device代码
/** 自定义设备框架* demoa.c*/#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 demo_open(struct mydev *this)
{printk(KERN_INFO "[%d]demo_open\n", this->minor);return 0;
}static int demo_close(struct mydev *this)
{printk(KERN_INFO "[%d]demo_close\n", this->minor);return 0;
}static ssize_t demo_read(struct mydev *this, char __user *buf, size_t count)
{printk(KERN_INFO "[%d]demo_read\n", this->minor);return 0;
}static ssize_t demo_write(struct mydev *this, const char __user *buf, size_t count)
{printk(KERN_INFO "[%d]demo_write\n", this->minor);return 0;
}static struct mydev_fops fops = {.owner       = THIS_MODULE,.my_read = demo_read,.my_write  = demo_write,.my_open  = demo_open,.my_close  = demo_close,
};static struct mydev mydev = {.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 ("gh");
MODULE_DESCRIPTION ("Driver for demo");
MODULE_SUPPORTED_DEVICE ("demo");module_init(demo_init);
module_exit(demo_exit);
3、include代码
//mydev.h
#ifndef MYDEV_H
#define MYDEV_H#define DYNAMIC_MINOR 256struct mydev;struct mydev_fops {struct module *owner;ssize_t (*my_read) (struct mydev *, char __user *, size_t);ssize_t (*my_write) (struct mydev *, const char __user *, size_t);long (*my_ioctl) (struct mydev *, unsigned int, unsigned long);int (*my_open) (struct mydev *);int (*my_close) (struct mydev *);
};struct mydev{const char *name;const struct mydev_fops *fops;void *private;//privateint major;int minor;struct device *thisdev;struct cdev *cdev;
};extern int add_mydev(struct mydev *);
extern int del_mydev(struct mydev *);#endif
/** 自定义设备框架* demob.c*/#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 demo_open(struct mydev *this)
{printk(KERN_INFO "[%d]demo_open\n", this->minor);return 0;
}static int demo_close(struct mydev *this)
{printk(KERN_INFO "[%d]demo_close\n", this->minor);return 0;
}static ssize_t demo_read(struct mydev *this, char __user *buf, size_t count)
{printk(KERN_INFO "[%d]demo_read\n", this->minor);return 0;
}static ssize_t demo_write(struct mydev *this, const char __user *buf, size_t count)
{printk(KERN_INFO "[%d]demo_write\n", this->minor);return 0;
}static struct mydev_fops fops = {.owner       = THIS_MODULE,.my_read = demo_read,.my_write  = demo_write,.my_open  = demo_open,.my_close  = demo_close,
};static struct mydev mydev = {.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 ("gh");
MODULE_DESCRIPTION ("Driver for demo");
MODULE_SUPPORTED_DEVICE ("demo");module_init(demo_init);
module_exit(demo_exit);

4、test代码

#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(0 > fd){perror("open");return -1;}printf("open done. fd=%d\n", fd);#define MAX 64char buf[MAX]={};int ret = write(fd, buf, MAX);if(0 > ret){perror("write");}printf("write done. fd=%d, ret=%d\n", fd, ret);ret = read(fd, buf, MAX);if(0 > ret){perror("read");}printf("read done. fd=%d, ret=%d\n", fd, ret);getchar();close(fd);printf("close done.\n");return 0;
}int main()
{demofunc("/dev/demo0");demofunc("/dev/demo1");
}
5、下载

https://download.csdn.net/download/u010872301/10467973

Linux驱动之分层框架相关推荐

  1. linux驱动分离分层的概念

    这个分离分层的概念和输入子系统有点像,但不是完全一样的.为什么会再弄一个这个模型出来我也没有搞懂,现在我的学习还停留在把知识学懂的层面上.至于为什么会产生这种知识,现在我还无从解释,还需时日成长. 这 ...

  2. Linux驱动学习--V4L2框架

    一.引言 V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动.在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0 ...

  3. Linux驱动学习--USB接口wifi/BT芯片开发之BT开发(BlueDroid框架)

    目录 一.引言 二.整体框架分析(结合实际芯片分析) 三.内核中的相关配置 四.厂家驱动分析 五.蓝牙BlueDroid协议 一.引言 之前我们简单分析过BlueDroid框架,今天来结合源码,挑重点 ...

  4. Linux驱动框架及详述(详细教程)

    Linux驱动框架及详述(详细教程) 1.前言 2.驱动程序的分类 3.设备驱动程序功能 4.驱动的基本框架 5.Hello驱动的编写 6.字符设备(LED)驱动程序编写实例 6.1 定义file_o ...

  5. 嵌入式linux驱动开发实战教程,嵌入式Linux驱动开发实战视频教程

    嵌入式Linux驱动开发实战教程(内核驱动.看门狗技术.触摸屏.视频采集系统) 适合人群:高级 课时数量:109课时 用到技术:嵌入式 Linux 涉及项目:驱动开发.看门狗技术.触摸屏.视频采集 咨 ...

  6. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED驱动框架--面向对象、分层设计思想

    文章目录 前言 1.LED驱动程序框架 1.1.对于LED驱动,我们想要什么样的接口? 1.2.LED驱动要怎么写,才能支持多个板子?分层写 1.3.程序分析 驱动程序 应用程序 Makefile 1 ...

  7. Linux设备驱动的分层设计思想

    1.1 设备驱动核心层和例化 在面向对象的程序设计中,可以为某一类相似的事物定义一个基类,而具体的事物可以继承这个基类中的函数.如果对于继承的这个事物而言,其某函数的实 现与基类一致,那它就可以直接继 ...

  8. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之驱动设计的思想:面向对象/分层/分离

    文章目录 前言 1.分离设计 驱动程序分析---程序分层 通用驱动程序---面向对象 个性化驱动程序---分离 APP 程序分析 前言 韦东山嵌入式Linux驱动开发基础知识学习笔记 文章中大多内容来 ...

  9. Linux驱动开发8 platform驱动分隔、分离与分层

            我们在前面几章编写的设备驱动都非常的简单,都是对IO进行最简单的读写操作.像I2C. SPI.LCD 等这些复杂外设的驱动就不能这么去写了,Linux 系统要考虑到驱动的可重用性,因 ...

最新文章

  1. android picasso源码下载,Picasso:一个专为Android制作的强大的图片下载和缓存库
  2. 【Java】6.2 处理对象
  3. 蓝牙模块怎么指定查询另一个蓝牙模块_蓝牙模块以IPEX端口外接天线、PCB板载天线最为常见...
  4. Oralce中日期格式
  5. jQuery无任何标示获取td在表格中的行数和列数
  6. java后台保存base64图片数据
  7. sklearn笔记之preprocessing
  8. 你这几天因为 YYYY-MM-dd 被提 BUG 了吗??
  9. android word分页,word文档如何设置分页以及取消分页
  10. linux 命令之(2)grep
  11. Android圆角ImageView的几种实现方式(包含四个角的分别设置)
  12. 根据日期推算星期和历法由来
  13. 【工具】Excel表格数据不能编辑
  14. Rust 管理员命令列表
  15. 光电耦合器原理及应用介绍
  16. 外贸网站如何全球加速?用全球加速CDN比较好
  17. Java8新特性函数式编程
  18. 外星人游戏本哪一款好?追求完美体验首选X系列
  19. android车载信息娱乐系统,基于Android的车载娱乐信息系统
  20. 解决方法:Win11下解决kali在vmware移动鼠标,鼠标在虚拟机和真实机来回切换的方法

热门文章

  1. linux ubuntu系统安装dotnet / Azcopy
  2. [tensorflow]tensorflow 2.1 函数API(The Functional API)
  3. Linux的哲学思想
  4. python hello world
  5. iOS Crash常规跟踪方法及Bugly集成运用
  6. 存储过程传递参数时出现类型转换错误!如:varchar转换为int时出错
  7. 将不确定变为确定~Linq to SQL不能随机排序吗?
  8. source insight 使用技巧
  9. java用poi实现对word读取和修改操作
  10. Android开源库集合(UI效果)