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 ...
随机推荐
- [转载]C++中 引用&与取地址&的区别
一个是用来传值的 一个是用来获取首地址的 &(引用)==>出现在变量声明语句中位于变量左边时,表示声明的是引用. 例如: int &rf; // 声明一个int型的引用r ...
- WebAPI接口测试之matthewcv.WebApiTestClient
WebAPI接口测试之matthewcv.WebApiTestClient matthewcv.WebApiTestClient 1.安装matthewcv.WebApiTestClient包 打开v ...
- DEDE站点从网站根目录移到子目录
修改DedeCms系统配置参数-站点设置 a.站点根网址修改为:http://域名/子目录 b.网页主页链接:/子目录 修改DedeCms系统配置参数-核心设置 a.安装目录:/子目录 批量修改原数据 ...
- Js屏蔽键盘事件
<script> function KeyDown(){ //屏蔽鼠标右键.Ctrl+n.shift+F10.F5刷新.退格键 //alert(& ...
- C语言基础学习基本数据类型-字符专属的输入输出函数
可以使用%c说明符以及scanf()和printf()函数来输入输出字符.现在我们将学习专门为面向字符而设计的一对函数:getchar()和putchar().getchar()函数没有参数,它返回来 ...
- IOS UITableView NSIndexPath属性讲解
IOS UITableView NSIndexPath属性讲解 查看UITableView的帮助文档我们会注意到UITableView有两个Delegate分别为:dataSource和deleg ...
- CentOS 6.x 下Postfix和dovecot邮件服务安装和基本配置
1 卸载sendmail [root@mail~]# pstree | grep sendmail [root@mail~]# service sendmail stop [root@mail~]# ...
- Hadoop 学习笔记(一) HDFS API
http://www.cnblogs.com/liuling/p/2013-6-17-01.html 这个也不错http://www.teamwiki.cn/hadoop/thrift thrift编 ...
- 【Java】环境变量的配置
注意点 1.环境变量不能有空格,比如C:\Program Files 2.JAVA_HOME:D:\Java\jdk1.7.0_67------------->注意不能加;分号
- 【JavsScript】关于javascript的路线
Client JS: Level 1 基本对象的掌握----------------------------------------->Library(兼容)/Widget(UI+功能)---- ...