linux设备驱动之misc驱动框架源码分析(二)

1、misc_open函数分析

该函数在driver/char/misc.c中,misc.c是驱动框架实现的,这里面的misc_Open函数是misc驱动框架为应用层提供的一个打开misc设备的一个接口。

1、首先我们要知道在misc.c中的misc_init函数中,将misc这种类设备注册成了字符设备驱动。代码如下

static int __init misc_init(void)
{
	int err;

#ifdef CONFIG_PROC_FS
	proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
	misc_class = class_create(THIS_MODULE, "misc");
	err = PTR_ERR(misc_class);
	if (IS_ERR(misc_class))
		goto fail_remove;

	err = -EIO;
	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))    //misc类的设备注册为字符设备驱动,因为使用的是register_chrdev函数。
		goto fail_printk;
	misc_class->devnode = misc_devnode;
	return 0;

fail_printk:
	printk("unable to get major %d for misc devices\n", MISC_MAJOR);
	class_destroy(misc_class);
fail_remove:
	remove_proc_entry("misc", NULL);
	return err;
}

上面代码中的register_chrdev函数参数中可以看出,misc_fops为包含了操作该驱动的方法结构体。结构体内容如下

static const struct file_operations misc_fops = {
	.owner		= THIS_MODULE,
	.open		= misc_open,
};

因此可以知道,驱动框架中的misc_open函数为驱动框架为应用层提供的接口,接口函数是open函数。正常来说,驱动框架中是不会写驱动的操作方法的,应该是留给我们驱动开发的人写的。自己去写这个file_operations结构体中的方法将其填充然后注册。

2、misc_open函数的代码分析,代码与分析如下

static int misc_open(struct inode * inode, struct file * file)
{
	int minor = iminor(inode);    //从传进来的参数中得到该设备的次设备号,inode是flash中文件的节点,file是打开的那一份的设备文件的路径
	struct miscdevice *c;    
	int err = -ENODEV;
	const struct file_operations *old_fops, *new_fops = NULL; //定义两个file_opreation结构体,这个结构体就不用说了,放的是接口函数,驱动
	                                                            //操作方法

	mutex_lock(&misc_mtx);

	list_for_each_entry(c, &misc_list, list) {    //遍历内核misc杂散类设备的链表,如果链表中存在这个设备的次设备号,那么就将内核链表中的
		if (c->minor == minor) {                //这个次设备号对应的设备的fops方法拿出来用,作为新的操作这个设备的方法。
			new_fops = fops_get(c->fops);
			break;
		}
	}

	if (!new_fops) {    //如果在内核misc链表中没有找到这个次设备号对应的fops,那么就request_module一次,在去找一次,如果还找不到,则
		mutex_unlock(&misc_mtx);                                    //跳到fail位置。在注册这个设备的时候,我们是会注册这个设备的fops 
		                                                            //的。
		                                                            //应用层用open操作这个设备的时候,对应到驱动层,就是先找到次设备
		                  //号,因为注册这个驱动的时候,fops已经提供了,同时,这个设备也注册了,所以去内核链表中找这个次设备号,
		                  //找到次设备号后就去找fops方法,找到后就得到这个fops结构体,正常来说是一定能找到的。因为驱动注册是你提供了
		                  //fops,设备创建注册时,也注册了对应的minor次设备号。
		request_module("char-major-%d-%d", MISC_MAJOR, minor);
		mutex_lock(&misc_mtx);

		list_for_each_entry(c, &misc_list, list) {
			if (c->minor == minor) {
				new_fops = fops_get(c->fops);
				break;
			}
		}
		if (!new_fops)
			goto fail;
	}

	err = 0;
	old_fops = file->f_op;    //将打开的文件的fop作为老的fop
	file->f_op = new_fops;    //将从misc内核链表中得到的fops作为新的ops给打开的。
	if (file->f_op->open) {    //如果得到了open的函数方法实例
		file->private_data = c;
		err=file->f_op->open(inode,file);    //然后调用open函数,这是真正的执行的open。上层用open操作misc设备时,最终执行的就是这个函
		                                     //数,这个被绑定到miscdevice结构体中的fops下的open,是写驱动的人提供的,在x210-buzzer.c
		                                     //提供的fops中的open
		if (err) {
			fops_put(file->f_op);
			file->f_op = fops_get(old_fops);
		}
	}
	fops_put(old_fops);
fail:
	mutex_unlock(&misc_mtx);
	return err;
}

因此应用层使用open操作misc设备的时候,会映射到驱动中的/driver/char/misc.c文件中的misc_open函数执行file->f_op->open函数,这个函数映射的是

/drvier/char/buzzer/x210-buzzer.c中的

static struct file_operations dev_fops = {
    .owner   =   THIS_MODULE,
    .open    =   x210_pwm_open,
    .release =   x210_pwm_close, 
    .ioctl   =   x210_pwm_ioctl,
};

里的open绑定的x210_pwm_open,x210_pwm_open的函数体是

static int x210_pwm_open(struct inode *inode, struct file *file)
{
	if (!down_trylock(&lock))
		return 0;
	else
		return -EBUSY;

}

2、misc在proc中的展现 proc不是很重要,因为proc文件系统现在用的越来越少,因为太乱,这里主要是为了让你知道这个代码是做什么的

cat /proc/misc文件时,会看到所有注册到misc中的设备的次设备号和名字,这个文件中的内容是通过遍历内核misc_list链表来显示出来的。

这个/proc/misc文件的创建是在/drvier/char/misc.c文件中的misc_init函数中的proc_create时创建的,代码如下

static int __init misc_init(void)
{
	int err;

#ifdef CONFIG_PROC_FS
	proc_create("misc", 0, NULL, &misc_proc_fops); //在/proc目录下创建出misc文件。
	                                                //misc_proc_fops结构体就是操作这个/proc/misc文件时的方法。
#endif

misc_proc_fops结构体内容为

static const struct file_operations misc_proc_fops = {
	.owner	 = THIS_MODULE,
	.open    = misc_seq_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release,
};

cat /proc/misc文件时对应的方法应该是

static const struct seq_operations misc_seq_ops = {
	.start = misc_seq_start,
	.next  = misc_seq_next,
	.stop  = misc_seq_stop,
	.show  = misc_seq_show,
};

中的misc_seq_show方法,内容如下

static int misc_seq_show(struct seq_file *seq, void *v)
{
	const struct miscdevice *p = list_entry(v, struct miscdevice, list);

	seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
	return 0;
}

3、内核互斥锁

(1)何为互斥锁?

和应用中的互斥锁其实差不多。别人访问时我不能访问,访问时别人访问,需要上锁和解锁,不多说,

(2)内核中定义互斥锁:DEFINE_MUTEX

(3)上锁:mutex_lock和解锁:mutex_unlock

(4)内核防止竞争状态的手段:原子访问、自旋锁、互斥锁、信号量

(5)原子访问主要是用来计数(访问过程不能被打断)、自旋锁后面说、互斥锁和信号量很相似(其实就是计数值为1的信号量),互斥锁的出现比信号量晚,实现上比信号量优秀,尽量使用互斥锁。

原子操作:

比如你定义一个变量count,然后count++,实际上这个count++是可以被打断的,因为count++转换成可能是三句代码,当执行了两句突然被打断时(可能是时间片时间到了),被打断时又改了这个count的值,那么这个时候这个count++的值肯定是不对的了,所以为了防止这种现象就有了原子操作,原子操作的计数不可以被打断。

自旋锁:自旋锁跟原子操作是有本质区别的,在现在的驱动中用的越来越多。是在多核CPU的年代发明的,专门应对这种多处理器的CPU的,所以自旋锁会用的越来越多,后面会详细说。

信号量:和互斥锁基本相似,信号量用来计数的,比如说一个设备只能被打开7次,每个人打开这个设备就会记一次数,当第八打开时,数为大于7了,就不能打开这个设备了。这就是用信号量来做的一个打开计数的手段。

互斥锁:互斥锁就是一种特殊的信号,他只能被打开一次。一个人打开了,数值可能就是1了,另一个人就不能打开了,当这个人解锁的时候,这个值就为0了,另一个人就可以打开或访问了。所以互斥锁和信号量的区别就是次数的区别。能用互斥锁的时候用互斥锁不要信号量。照猫画虎就行。如果驱动是你自己写的,你自己要去选择用互斥锁和信号量的时候,这个时候你已经不会纠结了,因为你有了自己不去照别人的驱动写驱动功力的时候,你就已经知道什么时候用互斥锁什么时候用信号量了。

misc.c这个内核人写的,写驱动框架人写的代码已经分析的差不多了,这部分代码只要理解就行,并不是驱动工程师需要去写的,我们要写的是驱动,而不是驱动框架代码。

后面分析的蜂鸣器的驱动代码,这部分代码是驱动工程师需要去写的。

时间: 2024-11-07 07:55:56

linux设备驱动之misc驱动框架源码分析(二)的相关文章

YII框架源码分析(百度PHP大牛创作-原版-无广告无水印)

                        YII 框架源码分析             百度联盟事业部--黄银锋   目 录 1. 引言 3 1.1.Yii 简介 3 1.2.本文内容与结构 3 2.组件化与模块化 4 2.1.框架加载和运行流程 4 2.2.YiiBase 静态类 5 2.3.组件 6 2.4.模块 9 2.5 .App 应用   10 2.6 .WebApp 应用   11 3.系统组件 13 3.1.日志路由组件  13 3.2.Url 管理组件  15 3.3.异常

android 网络框架 源码分析

android 网络框架 源码分析 导语: 最近想开发一个协议分析工具,来监控android app 所有的网络操作行为, 由于android 开发分为Java层,和Native层, 对于Native层我们只要对linux下所有网络I/O接口进行拦截即可,对于java 层,笔者对android 网络框架不是很了解,所以这个工具开发之前,笔者需要对android 的网络框架进行一个简单的分析. 分析结论: 1. android 的网络框架都是基于Socket类实现的 2. java 层Socket

Android Small插件化框架源码分析

Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github.com/wequick/Small 插件化的方案,说到底要解决的核心问题只有三个: 1.1 插件类的加载 这个问题的解决和其它插件化框架的解决方法差不多.Android的类是由DexClassLoader加载的,通过反射可以将插件包动态加载进去.Small的gradle插件生成的是.so包,在初始

携程DynamicAPK插件化框架源码分析

携程DynamicAPK插件化框架源码分析 Author:莫川 插件核心思想 1.aapt的改造 分别对不同的插件项目分配不同的packageId,然后对各个插件的资源进行编译,生成R文件,然后与宿主项目的R文件进行id的合并. 要求:由于最终会将所有的资源文件id进行合并,因此,所有的资源名称均不能相同. 2.运行ClassLoader加载各Bundle 和MultiDex的思路是一样的,所有的插件都被加载到同一个ClassLoader当中,因此,不同插件中的Class必须保持包名和类名的唯一

介绍开源的.net通信框架NetworkComms框架 源码分析

原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 售价249英镑 我曾经花了2千多购买过此通讯框架, 目前作者已经开源  许可是:Apache License v2 开源地址是:https://github.com/MarcFletcher/NetworkComms.Net 这个框架给我的感觉是,代码很优美,运行很稳定,我有一个项目使用此框架已经稳定运行1年多.这个框架能够

CodeIgniter框架——源码分析之入口文件index.php

CodeIgniter框架的入口文件主要是配置开发环境,定义目录常量,加载CI的核心类core/CodeIgniter.php. 源码分析如下: <?php //这个文件是入口,后期所有的文件都要在这里执行. /*----------------------------------------------- * 系统环境配置常量 * 能够配置错误显示级别 * ----------------------------------------------- * 默认情况下: * developmen

CodeIgniter框架——源码分析之CodeIgniter.php

CodeIgniter.php中加载了很多外部文件,完成CI的一次完整流程. <?php /** * 详见 http://www.phpddt.com/tag/codeIgniter/ */ //如果入口文件系统目录常量BASEPATH没定义,就挂了 if ( ! defined('BASEPATH')) exit('No direct script access allowed'); //定义常量:CI_VERSION,CI_CORE define('CI_VERSION', '2.1.4')

CodeIgniter框架——源码分析之Config.php

CI框架的配置信息被存储在$config数组中,我们可以添加自己的配置信息或配置文件到$config中: $this->config->load('filename'); //加载配置文件 $this->config->item('xxx'); //获取配置信息 当然也可以在autoload.php中设置默认加载! <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');   clas

iOS常用框架源码分析

SDWebImage NSCache 类似可变字典,线程安全,使用可变字典自定义实现缓存时需要考虑加锁和释放锁 在内存不足时NSCache会自动释放存储的对象,不需要手动干预 NSCache的key不会被复制,所以key不需要实现NSCopying协议 第三方框架 网络 1.PPNetworkHelper 对AFNetworking 3.x 与YYCache的二次封装 简单易用,包含了缓存机制,控制台可以直接打印json中文字符 2..YTKNetwork 猿题库研发团队基于AFNetworki

baksmali和smali源码分析(二)

这一节,主要介绍一下 baksmali代码的框架. 我们经常在反编译android apk包的时候使用apktool这个工具,其实本身这个工具里面对于dex文件解析和重新生成就是使用的baksmali 和smali这两个jar包其中 baksmali是将 dex文件转换成便于阅读的smali文件的,具体使用命令如下:java -jar baksmali.jar classes.dex -o myout其中myout是输出的文件夹 而smali是将smali文件重新生成回 dex文件的具体使用的命