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

本文介绍了一种分层驱动设计思路,包括应用层、接口层、核心层和设备驱动层。通过具体的代码示例展示了如何实现各层之间的交互,并提供了设备注册和注销的接口。

--------------------------------------------

应用层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);





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值