Linux驱动开发cdev驱动分层设计
#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驱动分层设计的更多相关文章
- (55)Linux驱动开发之一驱动概述
驱动 ...
- windows 驱动开发入门——驱动中的数据结构
最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...
- linux设备驱动的分层设计思想--input子系统及RTC
转自:linux设备驱动的分层设计思想 宋宝华 http://blog.csdn.net/21cnbao/article/details/5615493 1.1 设备驱动核心层和例化 在面向对象的程序 ...
- 《Linux设备驱动开发具体解释(第3版)》进展同步更新
本博实时更新<Linux设备驱动开发具体解释(第3版)>的最新进展. 2015.2.26 差点儿完毕初稿. 本书已经rebase到开发中的Linux 4.0内核,案例多数基于多核CORTE ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- 2019.05.08 《Linux驱动开发入门与实战》
第六章:字符设备 申请设备号---注册设备 1.字符设备的框架: 2.结构体,struct cdev: 3.字符设备的组成: 4.例子: 5.申请和释放设备号: 设备号和设备节点是什么关系.? 设备驱 ...
- (57)Linux驱动开发之三Linux字符设备驱动
1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...
- Linux驱动开发概述
原文出处:http://www.cnblogs.com/jacklu/p/4722563.html Linux设备分类 设备的驱动程序也要像裸机程序那样进行一些硬件操作,不同的是驱动程序需要" ...
- 驱动开发学习笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇
驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇下面这段摘自 linux源码里面的文档 : Documentatio ...
随机推荐
- Objective-C 笔记二 类、对象和方法
对象就是一个物件.面向对象的程序设计可以看成一个物件和你想对它做的事情.这与C语言不同,C语言通常称为过程性语言.在C语言中,通常是先考虑要做什么,然后才关注对象,这几乎总是与面相对象的思考过程相反. ...
- 设置Imindmap默认字体
创建一个新的字体样式 根据如下步骤创建新的字体样式: 1.打开一个mindmap,选中工具栏上的 [样式][Styles ]. 2.选择 Font > Create New Font Optio ...
- jsp中button传值
onclick=location.href("linker.jsp?custno="+ from1.custno.value)或者onClick ="a()" ...
- 错误:Duplicate interface definition for class
错误: Duplicate interface definition for class "类名称" 原因:在工程中有相同的文件或相同的 @interface 类名称 解决办法: ...
- jquery 文本框聚焦文字删除
做作业需要,自己写了一个,写的很烂. $(function() { $("#search_input").addClass("before_focus");/* ...
- [Git]Git安装
1.什么是Git Git是一个分布式版本控制/软件配置管理软件, git是用于Linux内核开发的版本控制工具, 与CVS.Subversion一类的集中式版本控制工具不同,它采用了分布式版本库的作法 ...
- JavaScript错误处理
JavaScript 错误 - Throw.Try 和 Catch JavaScript 测试和捕捉 try 语句允许我们定义在执行时进行错误测试的代码块. catch 语句允许我们定义当 try 代 ...
- php 数组 类对象 值传递 引用传递 区别
一般的数据类型(int, float, bool)不做这方面的解说了 这里详细介绍一下数组和的类的对象作为参数进行值传递的区别 数组值传递 实例代码: <?php function main() ...
- python -- 函数传参
一.参数传入规则 可变参数允许传入0个或任意个参数,在函数调用时自动组装成一个tuple: 关键字参数允许传入0个或任意个参数,在函数调用时自动组装成一个dict: 1. 传入可变参数: def ca ...
- Egret 矢量绘图、遮罩、碰撞检测
矢量绘图: 1. 为矢量绘图绘制外边 - graphics.lineStype() private createGameScene():void { console.log("Runtime ...