字符设备实现内部驱动原理及分步注册流程

这篇具有很好参考价值的文章主要介绍了字符设备实现内部驱动原理及分步注册流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

 字符设备实现内部驱动原理:

字符设备实现内部驱动原理及分步注册流程

 应用层:open函数回调到驱动中open操作方法的路线:

open()--->sys_open()--->struct inode结构体--->struct cdev结构体--->struct file_operations结构体--->mycdev_open()

字符设备驱动编写流程:

1、分配对象空间

2、对象空间的初始化

3、对象的注册

4、对象的注销

流程模板(非详细)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>

//定义cdev的结构体指针变量
struct cdev *cdev;
static int __init mycdev_init(void)
{
    //1.分配对象
 cdev = cdev_alloc();
    //2.对象的初始化
 cdev_init(cdev,&fops);
    //3.申请设备号,动态申请
 ret = alloc_chrdev_region(&devno,minor,count,CNAME);
    //4.字符设备驱动的注册
ret = cdev_add(cdev,MKDEV(major,minor),count);
    //5.自动创建设备节点
 cls = class_create(THIS_MODULE,CNAME);
 dev = device_create(cls,NULL,MKDEV(major,i),NULL,"mycdev%d",i);
    return 0;
}
static void __exit mycdev_exit(void)
{
    //1.销毁设备节点
        device_destroy(cls,MKDEV(major,i));
        class_destroy(cls);
    //2.销毁字符设备驱动
         cdev_del(cdev);
    //3.销毁设备号
unregister_chrdev_region(MKDEV(major,minor),count);
    //4.释放动态申请的cdev内存
kfree(cdev);

}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

 inode结构体作用:

只要文件存在文件系统中,在内核中就会有一个struct inode类型的空间,用于保存该文件的信息

struct file结构体作用:

open函数参数是路径下的文件名字,根据文件名找到inode号,然后根据inode结构体,回调对应的操作方法

通过文件描述符回调对应操作方法的路径:

fd--->fd_array[fd]--->struct file--->f_op--->操作方法

fd--->task_struct--->file struct(fd_array[fd])--->struct file--->f_op--->操作方法

linux内核中的并发和竟态解决方法:

当多个应用程序访问同一个驱动的临界资源的时候,竞态就会产生。

根本原因:

1.对于单核处理器,如果内核支持抢占就会产生竞态

2.多核处理器,核心与核心之间本身就会产生竞态。

3.中断和进程间也会产生竞态

解决方法:

1、中断屏蔽:

local_irq_disable();  //屏蔽中断
//临界资源
local_irq_enable();   //开启中断

2、自旋锁:

自旋锁:针对多核设计的,当一个进程获取到自旋锁之后,另外一个进程也想获取这把锁,此时后一个进程处于自旋状态(原地打转)(自旋锁又叫盲等锁);

特点:

1.自旋状态是需要消耗cpu资源的

2.自旋锁适合用在临界区比较小地方,临界区不能有延时,耗时,甚至休眠的操作,

临界区也不能够有copy_to_user/copy_from_user的函数。

3.自旋锁会导致死锁(在同一个进程中多次获取同一把未解锁的锁)

4.自旋锁可以在进程上下文中使用,也可以在中断上下文中使用

5.自旋锁在上锁前会关闭抢占

spinlock_t lock;        //定义自旋锁
spin_lock_init(&lock); //初始化自旋锁
spin_lock(&lock);      //上锁
spin_unlock(&lock);    //解锁

信号量:

信号量:当一个进程获取到信号量之后,另外一个进程也想获取信号量,此时后一个进程处于休眠状态。

特点:

1.休眠的进程是不消耗cpu资源的

2.信号量不会导致死锁

3.信号量保护的临界区可以很大,里面可以有延时,耗时,甚至休眠的操作。

4.信号量只能工作在进程上下文。不能工作于中断上下文。

5.信号量也不会关闭抢占

struct semaphore sem; //定义信号量
void sema_init(struct semaphore *sem, int val) //初始化信号量
//注意,这里的val只有初始化为1的时候才有能够解决竞态。当val初始化为0的时候代表同步机制
void down(struct semaphore *sem); //上锁
void up(struct semaphore *sem);//解锁

互斥体:

互斥体:当一个进程获取到互斥体之后,另外一个进程也想获取互斥体,此时后一个进程处于休眠状态。

特点:

1.休眠的进程是不消耗cpu资源的

2.互斥体不会导致死锁

3.互斥体保护的临界区可以很大,里面可以有延时,耗时,甚至休眠的操作。

4.互斥体只能工作在进程上下文。不能工作于中断上下文。

5.互斥体也不会关闭抢占

6.互斥体在进入休眠前会稍微等一会儿在进入休眠状态,但是对于临界区比较小的时候使用互斥体的效率是高于信号量的,优先使用互斥体

struct mutex mutex; //定义互斥体
mutex_init(&mutex); //初始化互斥体
void  mutex_lock(struct mutex *lock) //上锁
static int mutex_unlock(unsigned long *lock) //解锁

原子操作:

原子操作:将整个过程看做是一个不可被分割的整体。原子操作结构体内部本身就是一个变量,通过

对这个变量的值的修改来实现防止竞态的效果,对这个变量的值的修改是通过内联汇编完成的。文章来源地址https://www.toymoban.com/news/detail-485455.html

atomic_t atm = ATOMIC_INIT(1); //定义并初始化原子操作

int atomic_dec_and_test(atomic_t *v) //上锁
功能:让原子变量的值减去1,如果结果为0 表示获取锁成功了
参数:
    @v:原子变量的地址
返回值:如果获取成功返回真,失败返回假

void atomic_inc(atomic_t *v)   //将原子变量的值加1,解锁

atomic_t atm = ATOMIC_INIT(-1); //定义并初始化原子操作
int atomic_inc_and_test(atomic_t *v) //上锁
功能:让原子变量的值加1,如果结果为0 表示获取锁成功了
参数:
    @v:原子变量的地址
返回值:如果获取成功返回真,失败返回假
void atomic_dec(atomic_t *v)   //将原子变量的值减去1,解锁

到了这里,关于字符设备实现内部驱动原理及分步注册流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【IMX6ULL驱动开发学习】02.hello驱动程序之cdev注册字符设备驱动程序和设置次设备号

    目录 一、register_chrdev 二、解决方法 2.1 alloc_chrdev_region函数:注册一系列字符设备编号 2.2 cdev_init函数:初始化cdev结构体  2.3  cdev_add函数:将字符设备添加到系统中  三、驱动程序 【IMX6ULL驱动开发学习】01.编写第一个hello驱动+自动创建设备节点(不涉及硬件操作)_阿龙还

    2024年02月14日
    浏览(38)
  • 【linux驱动开发】在linux内核中注册一个杂项设备与字符设备以及内核传参的详细教程

    开发环境: windows + ubuntu18.04 + 迅为rk3568开发板 相较于字符设备,杂项设备有以下两个优点: 节省主设备号:杂项设备的主设备号固定为 10,在系统中注册多个 misc 设备驱动时,只需使用子设备号进行区分即可。 使用简单:相比如普通的字符设备驱动, misc驱动只需要将基本信

    2024年01月21日
    浏览(46)
  • 字符设备驱动读写操作实现

    put_user(x,ptr) x:char、int类型的简单变量名 get_user(x,ptr) x:char、int类型的简单变量名 mychar.c testmychar_app.c Makefile 实现结果: 改动之后的mychar.c代码 把这些全局变量封装在结构体中,这样可以更好地管理数据,降低代码的耦合性,提高代码的可维护性和可扩展性

    2024年02月10日
    浏览(37)
  • 4、Linux驱动开发:设备-设备号&设备号注册

    🍅点击这里查看所有博文   随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有

    2024年02月15日
    浏览(55)
  • 驱动开发--字符驱动设备2

    字符设备驱动 1.定义 以字节流的形式进行访问,且只能顺序访问的设备,针对字符设备编写的驱动叫做字符设备驱动 2.字符设备框架 用户空间通过IO函数如open、read、write、close等函数接口,调用内核空间中的字符设备驱动函数中的用户自定义的open、read、write、close等函数,通

    2024年02月15日
    浏览(41)
  • 字符设备驱动实例(ADC驱动)

            ADC是将模拟信号转换为数字信号的转换器,在 Exynos4412 上有一个ADC,其主要的特性如下。 (1)量程为0~1.8V。 (2)精度有 10bit 和 12bit 可选。 (3)采样时钟最高为5MHz,转换速率最高为1MSPS (4)具有四路模拟输入,同一时刻只有一路进行转换 (5) 转换完成后可以产生中断。

    2024年02月11日
    浏览(38)
  • 【IMX6ULL驱动开发学习】08.马达驱动实战:驱动编写、手动注册平台设备和设备树添加节点信息

    目录 一、使用设备树 1.1 修改设备树流程 二、手动创建平台设备  三、总结(附驱动程序) 前情提要:【IMX6ULL驱动开发学习】07.驱动程序分离的思想之平台总线设备驱动模型和设备树_阿龙还在写代码的博客-CSDN博客 手动注册平台设备和设备树的目的都是为了构造platform_de

    2024年02月12日
    浏览(52)
  • Linux 驱动学习笔记 ——(1)字符设备驱动

    《【正点原子】I.MX6U嵌入式Linux驱动开发指南》学习笔记 字符设备是 Linux 驱动中最基本的一类设备驱动,字节设备就是按照字节流来读写的设备,常见的字符设备包括:LED、蜂鸣器、按键、I2C 以及 SPI 等。 Linux 中一切皆文件,字符设备驱动加载成功后会在 /dev 目录下生成相

    2024年02月08日
    浏览(55)
  • Linux设备驱动——第三章字符驱动

    当对幸福的憧憬过于急切,那痛苦就在人的心灵深处升起。——加缪 本章的目的是编写一个完整的字符设备驱动。我们开发一个字符驱动是因为这一类适合大部分简单的硬件设备。字符驱动也比块驱动易于理解。本章的最终目的是编写一个模块化的字符驱动,但是我们不会在

    2024年02月08日
    浏览(80)
  • 字符设备驱动

    前面内容: 1 Linux驱动—内核模块基本使用 2 Linux驱动—内核模块参数,依赖(进一步讨论) linux根据驱动程序实现的模型框架将设备的驱动分为了三类: 字符设备驱动:以字节流为单位顺序读写,不能随机访问。如,帧缓冲 ( framebuffer)驱动,声卡,串口等。 块设备驱动:以固定

    2023年04月08日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包