您的位置:首页 > 运维架构 > 网站架构

主动分层设计的驱动子系统架构模拟

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 系统架构 设计