misc类设备驱动3——misc驱动框架源码分析(核心层+具体操作层)

以下内容源于朱有鹏嵌入式课程的学习与整理,如有其侵权请告知删除。

前言

由misc类设备驱动1——misc类设备的简介可知,misc类设备驱动框架包括以下两部分:

1、内核开发者实现的部分

drivers/char/misc.c文件主要包括2个关键点:类的创建、开放给驱动开发者的接口。


2、驱动工程师实现的部分

比如蜂鸣器驱动x210_kernel\drivers\char\buzzer\x210-buzzer.c文件。

下面将对misc.c文件、x210-buzzer.c文件进行分析。

一、驱动核心层misc.c文件的分析

1、misc_init()函数

misc类设备驱动框架本身也是一个模块(这意味着可裁剪),内核启动时自动加载。

subsys_initcall(misc_init);

misc_init()函数内容如下:

static int __init misc_init(void)
{int err;#ifdef CONFIG_PROC_FSproc_create("misc", 0, NULL, &misc_proc_fops);
#endifmisc_class = class_create(THIS_MODULE, "misc");//注册/sys/class/misc类err = PTR_ERR(misc_class);if (IS_ERR(misc_class))goto fail_remove;err = -EIO;         //10   使用老接口注册字符设备驱动(主设备号10)if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))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;
}
subsys_initcall(misc_init);

(1)该函数的主要工作内容

使用class_create()函数注册了misc类,因此可以在/sys/class/目录下找到misc目录。

使用register_chrdev()这个老接口字符设备驱动注册函数,注册了主设备号为10的字符设备驱动。因此"cat /proc/devices"时,字符设备列表处显示有“10 misc”。

存疑:/dev/buzzer这个设备文件是在哪里在什么时候创建的?这个设备文件在x210-buzzer.c文件中的misc_register()函数中创建。

(2)misc_fops变量的定义

使用register_chrdev()这个老接口字符设备驱动注册函数时,参数中有misc_fops这个变量,其定义如下。其中misc_open()函数的分析下文。

static const struct file_operations misc_fops = {.owner		= THIS_MODULE,.open		= misc_open,//分析见下文
};


2、misc_register()函数

驱动框架设计了杂散设备的注册接口:misc_register()。驱动工程师借助misc类设备驱动框架编写驱动时,只需要调用misc_register()函数注册自己的设备即可,其余均不用管。

misc_register()函数内容如下:

int misc_register(struct miscdevice * misc)
{struct miscdevice *c;dev_t dev;int err = 0;INIT_LIST_HEAD(&misc->list);//(1)misc_list链表的作用mutex_lock(&misc_mtx);//遍历内核链表,查看该次设备号是否已经被占用list_for_each_entry(c, &misc_list, list) {if (c->minor == misc->minor) {//次设备号已经被占用mutex_unlock(&misc_mtx);return -EBUSY;}}if (misc->minor == MISC_DYNAMIC_MINOR) {//这个表示自动分配次设备号int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);if (i >= DYNAMIC_MINORS) {mutex_unlock(&misc_mtx);return -EBUSY;}misc->minor = DYNAMIC_MINORS - i - 1;set_bit(i, misc_minors);//这个表示我要占用此次设备号}dev = MKDEV(MISC_MAJOR, misc->minor);//合成设备号misc->this_device = device_create(misc_class, misc->parent, dev,misc, "%s", misc->name);//创建设备文件if (IS_ERR(misc->this_device)) {int i = DYNAMIC_MINORS - misc->minor - 1;if (i < DYNAMIC_MINORS && i >= 0)clear_bit(i, misc_minors);err = PTR_ERR(misc->this_device);goto out;}/** Add it to the front, so that later devices can "override"* earlier defaults*/list_add(&misc->list, &misc_list);out:mutex_unlock(&misc_mtx);return err;
}

(1)struct miscdevice 结构体

该结构体是对一个杂散设备的抽象,或者说该结构体的变量表示一个杂散设备。

此结构体定义在x210_kernel\include\linux\miscdevice.h文件中,内容如下:

struct miscdevice  {int minor; //杂散设备的主设备号规定为10,可变的仅有次设备号const char *name; //杂散设备的名字const struct file_operations *fops;//文件操作函数指针struct list_head list;struct device *parent;struct device *this_device;const char *nodename;mode_t mode;
};

(2)misc_list链表的作用

在misc.c文件开头处,定义了一个misc_list链表,即“ static LIST_HEAD(misc_list); ”,用来记录所有内核中注册了的杂散类设备(P.s. 之前的字符设备,是固定大小(255)的数组)。

当我们向内核注册一个misc类设备时,内核就会向misc_list链表中插入一个节点。当使用cat /proc/misc打印出信息时,其实就是遍历此链表。

static LIST_HEAD(misc_list);/*
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)因此上面式子展开后等价于
static struct list_head misc_list = { &(misc_list), &(misc_list) }*/

3)主设备号和次设备号的作用和区分

主设备号表示类,次设备号表示某具体设备。

3、misc_open()函数

之前说到,misc_fops这个变量中的成员open函数,指向misc_open()函数。

static const struct file_operations misc_fops = {.owner		= THIS_MODULE,.open		= misc_open,//分析见下文
};

misc_open()函数代码如下:

static int misc_open(struct inode * inode, struct file * file)
{                    //文件在硬盘的路径      //设备文件的路径int minor = iminor(inode);struct miscdevice *c;int err = -ENODEV;const struct file_operations *old_fops, *new_fops = NULL;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) {mutex_unlock(&misc_mtx);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;file->f_op = new_fops;if (file->f_op->open) {file->private_data = c;err=file->f_op->open(inode,file);//主要的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;
}

misc_open()函数最终映射到x210_buzzer.c中的open函数

4、misc设备在proc文件系统下的展现

通过"cat /proc/devices"时,字符设备列表处显示有“10 misc”。如下所示。

[root@xjh proc]# cat devices 
Character devices:1 mem
//省略部分代码7 vcs10 misc  //这里出现主设备号为10,名字为misc的字符设备13 input
//省略部分代码Block devices:
//省略部分代码
254 device-mapper

5、内核互斥锁

(1)内核用于防止竞争状态的手段包括:原子访问、自旋锁、互斥锁、信号量。

关于这些手段的介绍,可见博客:内核中防止竞争状态的手段 - 涛少& - 博客园

(2)static DEFINE_MUTEX(misc_mtx);

在misc.c文件开头处有如下代码:

static DEFINE_MUTEX(misc_mtx);

DEFINE_MUTEX这个宏包含在x210_kernel\include\linux\mutex.h文件中,如下:

#define DEFINE_MUTEX(mutexname) \struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)/*
#define __MUTEX_INITIALIZER(lockname) \{ .count = ATOMIC_INIT(1) \, .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \, .wait_list = LIST_HEAD_INIT(lockname.wait_list) \__DEBUG_MUTEX_INITIALIZER(lockname) \__DEP_MAP_MUTEX_INITIALIZER(lockname) }
*/

所以static DEFINE_MUTEX(misc_mtx);展开后成为:

struct mutex misc_mtx = {        .count = ATOMIC_INIT(1) ,.wait_lock = __SPIN_LOCK_UNLOCKED(misc_mtx.wait_lock) ,.wait_list = LIST_HEAD_INIT(misc_mtx.wait_list) ,   };

(3)上锁mutex_lock和解锁mutex_unlock

要访问某资源时,要给该资源上锁;使用完后,要解锁。当某进程想访问已经被上锁的资源时,会休眠,直到其他进程解锁后此进程才能访问该资源。


三、具体操作层x210-buzzer.c文件的分析

1、dev_init()函数

蜂鸣器归类为杂项字符设备,其驱动文件是x210-buzzer.c,它也属于模块化设计。

module_init(dev_init);

该函数的内容如下:

static int __init dev_init(void)
{int ret;init_MUTEX(&lock);ret = misc_register(&misc);//接下来对硬件,即蜂鸣器进行初始化//向gpiolib申请gpio,并设置成上拉、输出模式,输出值为0 /* GPD0_2 (PWMTOUT2) *///由原理图得知蜂鸣器的接口是GPD0_2ret = gpio_request(S5PV210_GPD0(2), "GPD0");//向gpiolib申请gpioif(ret)printk("buzzer-x210: request gpio GPD0(2) fail");s3c_gpio_setpull(S5PV210_GPD0(2), S3C_GPIO_PULL_UP);//设置成上拉s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(1));//设置成输出模式gpio_set_value(S5PV210_GPD0(2), 0);//设置输出值为0 printk ("x210 "DEVICE_NAME" initialized\n");return ret;
}

(1)互斥锁初始化:init_MUTEX(&lock)

互斥锁其实就是计数值为1的信号量,所以sema_init(sem, 1)中参数设为1。

有待深入。open和release函数里面也有互斥锁。

init_MUTEX(&lock);/*
#define init_MUTEX(sem)   sema_init(sem, 1) //这里参数为1static inline void sema_init(struct semaphore *sem, int val)
{static struct lock_class_key __key;*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
}
*/

(2) misc_register(&misc)中的变量misc

变量misc的数据类型是struct miscdevice,该变量定义如下。

static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,//其值为255,表示自动分配次设备号.name = DEVICE_NAME,.fops = &dev_fops,
};

(3)gpio_request

(4)printk

2、x210_pwm_ioctl()函数

该函数的内容如下:

// PWM:GPF14->PWM0
static int x210_pwm_ioctl(struct inode *inode, struct file *file, \unsigned int cmd, unsigned long arg)
{switch (cmd) {case PWM_IOCTL_SET_FREQ:printk("PWM_IOCTL_SET_FREQ:\r\n");if (arg == 0)return -EINVAL;PWM_Set_Freq(arg);break;case PWM_IOCTL_STOP:default:printk("PWM_IOCTL_STOP:\r\n");PWM_Stop();break;}return 0;
}
//上面这两个宏按理定义在头文件中,然后让应用程序包含
//但是这个文件却直接定义在开头了!不规范!

(1)为什么会有ioctl这个函数?

ioctl函数是对设备进行输入与输出,既然如此,为何不用read和write函数呢?其实只有read和write函数也是可以的,之前的驱动没有ioctl函数也可以工作。但read和write函数会导致应用层和驱动层的交互麻烦。比如写驱动的人在驱动中定义亮灭,应用层的人怎么知道呢?使用ioctr后,通过命令码的名字就可以明确知道命令码含义。

(2)ioctl的使用方法

在应用层编写代码,见misc类设备驱动0——板载蜂鸣器驱动测试

3、硬件操作有关的代码

硬件操作有关的代码,是指PWM_Set_Freq()函数、PWM_Stop()函数。

PWM_Set_Freq()函数

// TCFG0在Uboot中设置,这里不再重复设置
// Timer0输入频率Finput=pclk/(prescaler1+1)/MUX1
//                     =66M/16/16
// TCFG0 = tcnt = (pclk/16/16)/freq;
// PWM0输出频率Foutput =Finput/TCFG0= freq
static void PWM_Set_Freq( unsigned long freq )
{unsigned long tcon;unsigned long tcnt;unsigned long tcfg1;struct clk *clk_p;unsigned long pclk;//unsigned tmp;//设置GPD0_2为PWM输出s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(2));tcon = __raw_readl(S3C2410_TCON);tcfg1 = __raw_readl(S3C2410_TCFG1);//mux = 1/16tcfg1 &= ~(0xf<<8);tcfg1 |= (0x4<<8);__raw_writel(tcfg1, S3C2410_TCFG1);clk_p = clk_get(NULL, "pclk");pclk  = clk_get_rate(clk_p);tcnt  = (pclk/16/16)/freq;__raw_writel(tcnt, S3C2410_TCNTB(2));__raw_writel(tcnt/2, S3C2410_TCMPB(2));//占空比为50%tcon &= ~(0xf<<12);tcon |= (0xb<<12);	//disable deadzone, auto-reload, inv-off, //update TCNTB0&TCMPB0, start timer 0__raw_writel(tcon, S3C2410_TCON);tcon &= ~(2<<12);			//clear manual update bit__raw_writel(tcon, S3C2410_TCON);
}

(1)此函数用于打开蜂鸣器并设置想要的频率。

(2)蜂鸣器分为有源蜂鸣器,无源蜂鸣器。有源蜂鸣器可以用PWM信号驱动并改变频率,无源蜂鸣器好像不可以?这里是有源蜂鸣器。

PWM_Stop()函数

void PWM_Stop( void )
{//将GPD0_2设置为inputs3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(0));	
}

(1)此函数用于关闭蜂鸣器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/460589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mint锁屏设置

心血来潮&#xff0c;给笔记本装了linux&#xff0c;版本是当下最火的mint。唔&#xff0c;使用体验不错&#xff5e;下面记录的是修改mint锁屏相关设置的修改方式。 In Linux Mint 13, the screen lock feature is disabled by default. After being idle for a while, the sc…

effective C++ 读后笔记

首先不得不说侯捷翻译的书大部分我都很喜欢&#xff0c;因为侯捷本身是一名出色的C技术专家。这本书讲的是C如何高效的运行&#xff0c;我想要成为一名卓越的开发人员&#xff0c;代码的高效性是必不可少的。很多人的代码质量很差&#xff0c;即使能够勉强运行在以后的维护和重…

【百度地图API】如何制作班级地理通讯录?LBS通讯录

原文:【百度地图API】如何制作班级地理通讯录&#xff1f;LBS通讯录摘要&#xff1a;班级通讯录必备的功能&#xff0c;比如人员列表&#xff0c;人员地理位置标注&#xff0c;展示复杂信息窗口&#xff0c;公交和驾车等。一般班级人员都不会超过300个&#xff0c;因为可以高效…

开发板——在X210开发板上进行裸机开发的流程

流程总结 本文以“LED流水灯”为例&#xff0c;说明在X210开发板上进行裸机开发的流程。 步骤一&#xff1a;搭建嵌入式Linux开发环境 在虚拟机中安装与配置Linux系统&#xff0c;并安装交叉编译工具链&#xff1b; 在win主机上安装dnw软件、九鼎烧写SD卡软件等内容。 步骤二&a…

zmail邮件系统安装手册 V2.0版本

2019独角兽企业重金招聘Python工程师标准>>> Tmail邮件系统安装手册 V2.0版本 1、系统环境 centos6.0以上&#xff0c;最小化安装(64位系统) 2、部署 1、删除自带的postfix、mysql、httpd # rpm -qa|grep postfix|xargs rpm -e --nodeps # rpm -qa|grep mysql|xargs…

Cassandra1.2文档学习(5)—— Snitch

参考资料&#xff1a;http://www.datastax.com/documentation/cassandra/1.2/webhelp/index.html#cassandra/architecture/architectureSnitchesAbout_c.html#concept_ds_c34_fqf_fk 一个snitch&#xff08;告密者&#xff09;决定应当从哪个数据数据中心和机架写入和读取数据。…

Entity Framework在WCF中序列化的问题(转)

问题描述 如果你在WCF中用Entity Framework来获取数据并返回实体对象&#xff0c;那么对下面的错误一定不陌生。 接收对 http://localhost:5115/ReService.svc 的 HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。 这还可能是由于服务器中止了 HTTP …

【iHMI43 4.3寸液晶模块】demo例程(版本1.03)发布

技术论坛&#xff1a;http://www.eeschool.org 博客地址&#xff1a;http://xiaomagee.cnblogs.com 官方网店&#xff1a;http://i-board.taobao.com 银杏科技 GINGKO TECH. 保留权利&#xff0c;转载请注明出处 一、简介&#xff1a; 1、iHMI43 演示程序(版本号&#xff1a;1…

SDRAM——X210的SDRAM的初始化

以下内容源于朱友鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 参考博客&#xff1a;s5pv210——初始化SDRAM - biaohc - 博客园 这里说的SDRAM&#xff0c;简单点理解就是内存。 一、SDRAM的简介 1、SDRAM的含义 SDRAM是Syncronized Dynamic Ramdam Access Me…

安卓开发.四大组件.activity.1

安卓开发.四大组件.activity.1 转载于:https://www.cnblogs.com/motadou/p/3534056.html

单独一台机器测试Open×××加密隧道的问题和解决

其实这篇文章和Open的关系倒不是很大&#xff0c;只是通过Open测试时暴露出的问题。这篇文章里面倒是包含了很多IP路由以及conntrack的细节内容。 有时候&#xff0c;为了节省机器&#xff0c;我希望在一台设备上模拟多个设备&#xff0c;当然&#xff0c;使用网络命名空…

SCRT中只换行不回车的问题(阶梯)

转载源&#xff1a;SecureCRT中只换行不回车的问题 - 知乎 在SecureCRT中有时会遇到由于Windows的换行和Unix的换行控制字符不同的问题&#xff08;\r\n-\n&#xff09;&#xff0c;导致显示如下图所示的“阶梯”&#xff0c;又不想到源码中一个个改控制字符&#xff0c;此时可…

Android Training精要(六)如何防止Bitmap对象出现OOM

1.使用AsyncTask異步加載bitmap圖片避免OOM: class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> { private final WeakReference<ImageView> imageViewReference; private int data 0; public BitmapWorkerTask(ImageView imageView) { // Use a …

iOS会议和组织

全世界有许多iOS会议和组织&#xff0c;如果你没有机会去参加&#xff0c;知道他们的存在和向他们学习对你也是有益的。事实上&#xff0c;他们中有些提供免费的幻灯片、视频&#xff0c;有用资料等&#xff0c;所以你不能够忽视他们。 有一些会议的主题并不仅仅关于iOS的&…

开发板——X210开发板的软开关(供电置锁)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、前言 本章节在裸机课程的SD卡启动部分。 本文讲述如何设置开发板&#xff0c;使得一按下电源键程序运行后即可松手不会断电&#xff0c;即供电置锁。 二、软开关的简介 电路设计一般使用拨码开…

国产Linux软件

为什么80%的码农都做不了架构师&#xff1f;>>> 本页面收集支持deepin/Linux的国产软件&#xff0c;对于每款软件以“日出东方-发行时间较短&#xff1b;正当壮年-时间较长且稳定&#xff1b;每况愈下-你们懂的”评价 软件版本时间评价有道词典 Linux版1.02015-03…

QGLViewer 编译安装步骤

由于工作学习的需要&#xff0c;要用opengl绘制显示些模型动画&#xff0c;原来用的是Qt做UI&#xff0c;直接调用的是QGLWidget类&#xff0c;但这个只是提供了基本的框架&#xff0c;很多交互操作还需添加代码完成&#xff0c;自己偷懒也觉得繁琐&#xff0c;就借用了开源的工…

触摸屏——S5PV210的触摸屏的理论与操作

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有其侵权请告知删除。 一、输入类设备简介 1、input/output 输入输出&#xff0c;是计算机系统中的一个概念。计算机可以看作数据处理器。计算机的主要功能就是从外部获取数据&#xff0c;然后进行计算加工得到输出数据…

搭建nginx流媒体服务器(支持HLS)

环境搭建 &#xff08;一&#xff09;下载源代码 nginx&#xff0c;地址&#xff1a;http://nginx.org/可以选择需要的版本下载 nginx_mod_h264_streaming-2.2.7.tar.gz &#xff0c;支持MP4流&#xff0c;具体的说明在下面的这个网页 http://h264.code-shop.com/trac/wiki/Mod…

Spring中的动态代理

动态代理&#xff1a;指的就是通过一个代理对象来创建需要的业务对象&#xff0c;然后在这个代理对象中统一进行各种需求的处理。 学习完Spring后会发现&#xff0c;Spring中的AOP&#xff08;面向方面编程&#xff1a;Aspect Oriented Programming&#xff09;是个很重要的知识…