主动分层设计的驱动子系统架构模拟
2017-07-12 14:02
393 查看
--------------------------------------------
应用层application
--------------------------------------------
接口层interface
--------------------------------------------
核心层core
--------------------------------------------
设备驱动层device-driver
--------------------------------------------
/*************************************************************************
* 分层分工设计演示
* cdev为接口层
* 实际中可以将 接口层 和 核心层 单独文件
*************************************************************************/
#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 const char mydevname[] = "mydev";
//=================================================接口层======================================================
//接口层准备与应用层交互的接口,做准备工作
static struct class *mydevclass = NULL;
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);
/* ******************************************************************
* 标准设备打开接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的open方法
******************************************************************/
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;
}
/* ******************************************************************
* 标准设备release接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的releasei(close)方法
******************************************************************/
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;
}
/* ******************************************************************
* 标准设备read接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的read方法
******************************************************************/
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;
}
/* ******************************************************************
* 标准设备write接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的write方法
******************************************************************/
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];
}
/* ***********************************************************
* 提供给设备层 注册 设备接口
* 每添加一个设备,调用
* 1. 分配一个未使用的次设备号
* 2. 创建一个对应的字符设备
* 2.1 动态申请设备号
* 2.2 添加操作方法集
* 3. 设备添加到设备表对应位置(核心层维护设备表)
* 这里的字符设备创建就是给应用层提供操作接口,
* 这里核心层和接口层并不明显进行区分
* ***********************************************************/
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;
}
// 1.
obj->minor = i;
// 2.
i = setup_cdev(obj);
if(i){
return i;
}
// 3.
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_DESCRIPTION ("Driver for mydev");
MODULE_SUPPORTED_DEVICE ("mydev");
/**********************************************************
* 自定义设备框架--设备层
* 设备层解决具体操作设备相关的驱动接口
* 设备层向下直接同硬件交互,向上提供数据
* 设备层的注册注销接口由核心层提供
**********************************************************/
#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,
};
// 静态构造一个mydev设备对象mydev 并用对应的操作方法集初始化
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_DESCRIPTION ("Driver for demo");
MODULE_SUPPORTED_DEVICE ("demo");
module_init(demo_init);
module_exit(demo_exit);
应用层application
--------------------------------------------
接口层interface
--------------------------------------------
核心层core
--------------------------------------------
设备驱动层device-driver
--------------------------------------------
/*************************************************************************
* 分层分工设计演示
* cdev为接口层
* 实际中可以将 接口层 和 核心层 单独文件
*************************************************************************/
#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 const char mydevname[] = "mydev";
//=================================================接口层======================================================
//接口层准备与应用层交互的接口,做准备工作
static struct class *mydevclass = NULL;
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);
/* ******************************************************************
* 标准设备打开接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的open方法
******************************************************************/
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;
}
/* ******************************************************************
* 标准设备release接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的releasei(close)方法
******************************************************************/
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;
}
/* ******************************************************************
* 标准设备read接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的read方法
******************************************************************/
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;
}
/* ******************************************************************
* 标准设备write接口,类比接口类或者抽象基类
* 每次应用层调用到该方法时
* 1. 根据次设备号找到要操作的设备对象指针
* 2. 调用设备对应的具体操作方法中的write方法
******************************************************************/
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];
}
/* ***********************************************************
* 提供给设备层 注册 设备接口
* 每添加一个设备,调用
* 1. 分配一个未使用的次设备号
* 2. 创建一个对应的字符设备
* 2.1 动态申请设备号
* 2.2 添加操作方法集
* 3. 设备添加到设备表对应位置(核心层维护设备表)
* 这里的字符设备创建就是给应用层提供操作接口,
* 这里核心层和接口层并不明显进行区分
* ***********************************************************/
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;
}
// 1.
obj->minor = i;
// 2.
i = setup_cdev(obj);
if(i){
return i;
}
// 3.
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_DESCRIPTION ("Driver for mydev");
MODULE_SUPPORTED_DEVICE ("mydev");
/**********************************************************
* 自定义设备框架--设备层
* 设备层解决具体操作设备相关的驱动接口
* 设备层向下直接同硬件交互,向上提供数据
* 设备层的注册注销接口由核心层提供
**********************************************************/
#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,
};
// 静态构造一个mydev设备对象mydev 并用对应的操作方法集初始化
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_DESCRIPTION ("Driver for demo");
MODULE_SUPPORTED_DEVICE ("demo");
module_init(demo_init);
module_exit(demo_exit);
相关文章推荐
- 领域驱动设计-学习笔记 分层架构
- 领域驱动设计(一)理解分层架构
- 领域驱动设计中面向经典分层架构的领域事件的设计与实现
- 领域驱动设计-学习笔记 分层架构
- 领域驱动设计之设计分层架构
- 领域驱动设计中面向经典分层架构的领域事件的设计与实现
- IDDD 实现领域驱动设计-架构之经典分层
- 领域驱动设计的标准分层架构
- 基于.NET平台的分层架构实战(四)实体类的设计与实现
- 基于.NET平台的分层架构实战(五)——接口的设计与实现
- 基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现
- 领域驱动设计:理念,架构和若干重要细节(draft)
- 基于.NET平台的分层架构实战(五)接口的设计与实现
- 基于.NET平台的分层架构实战(四)——实体类的设计与实现
- 领域驱动设计之--基本架构(转)
- 基于.NET平台的分层架构实战(五)——接口的设计与实现
- 基于.NET平台的分层架构实战(六)——依赖注入机制及IoC的设计与实现
- 基于.NET平台的分层架构实战(二)需求分析与数据库设计
- 基于.NET平台的分层架构实战(三)架构概要设计
- 基于.NET平台的分层架构------依赖注入机制及IoC的设计与实现