文章目录

  • 知识框图:
    • 驱动
      • 字符设备驱动框架
      • 模块传参与符号导出
      • 最简单的字符设备驱动LED灯
    • IO模型
      • 阻塞
      • 非阻塞
      • IO多路复用
      • 异步通知--信号驱动
    • 中断与时钟
      • 中断底半部
      • 定时器
    • 内存分配
    • 设备模型
      • 本质思想
      • bus-dev-dri模型
      • 匹配过程描述:
    • platform总线
    • IIC总线
      • 从这个函数开始看起:i2c_add_driver(&mpu6050)
      • IIC分层模型
      • IIC简单框架搭建
      • 看透IIC设备的本质:
    • 输入子系统
    • 设备树

知识框图:

驱动

字符设备驱动框架

  1. 向下操作硬件
    硬件的初始化 发送接收

  2. 向上提供接口
    file_operations fops

  3. 三要素
    模块加载module_init
    模块卸载 module_exit
    模块授权 module_license

  4. 创建设备节点
    手动创建:mknod /dev/devname c major minor
    自动创建:

      class_create(owner, name)  device_create(cls, null, MKDEV(major,0),null, "devname", ...)
    

模块传参与符号导出

  1. 参数传递:数组 - 指针 - 字符串 -整形
  2. EXPORT_SYMBOL(xxx)
  3. 模块动态和静态注册: register_chrdev()

最简单的字符设备驱动LED灯

  1. 驱动层:只负责灯的亮 - 灭 (硬件正常工作功能部分),然后提供接口给上层去操作
  2. 应用层:考虑灯怎么亮,怎么灭,亮多久,灭多久,主要负责逻辑部分
  3. 疑问?当多个应用来调用我这一个驱动的时候会出现什么问题?

IO模型

https://blog.csdn.net/Set_Mode/article/details/94356904

阻塞

没有数据睡眠等
有数据唤醒读

非阻塞

有无数据全部立即返回

IO多路复用

poll机制

  1. 驱动层:poll_wait函数轮询fd,查看那个设备准备就绪,如果就绪则mask = POLLIN,返回给应用层的revents,执行其他操作
  2. 应用层:可以通过poll epoll select来调用底层的poll函数实现多路检测, 关键结构体的填充

异步通知–信号驱动

  1. 驱动层:接收应用层传递的fd信息,回调fd结构体中的fasync函数,回调fasync_helper,关键结构体填充后,当数据准备就绪后,调用kill_fasync函数通知应用层数据准备就绪,应用层调用信号处理函数
  2. 应用层:open获得fd,通过fcntl获取flags标志位,然后修改flags | FASYNC,设置属主进程fcntl(fd,FD_OWN,getpid()),设置信号检测和回调函数 signal(SIGIO,handler)

中断与时钟

中断底半部

  1. 软中断
    暂时没有研究
  2. tasklet
    工作在中断上下文 — 不能有耗时操作 ,不能有调度
  3. workqueue
    工作在进程上下文,可以有调度

定时器

   (jiffies  + HZ  ) - jiffies  = 1sstruct timer_list mytimer;init_timer(&key->mytimer); //初始化定时器key->mytimer.function = do_timer_handler; //填充中断处理函数key->mytimer.expires  = jiffies +2 * HZ;  //设置定时时间add_timer(&key->mytimer);  //添加定时器void do_timer_handler(unsigned long delay){printk("do_timer_handler >>>......\n");mod_timer(&key->mytimer,jiffies +3 * HZ);  //重新开启定时器}

内存分配

  1. kmalloc ------ 物理和虚拟都连续 —32B – 128K
  2. __get_free_pages() ----物理和虚拟都连续 4K
  3. vmalloc ----虚拟连续,物理不一定连续

设备模型

本质思想

是设备和驱动分离,减少设备端和驱动端的编写

bus-dev-dri模型

类型 说明
struct bus_type int (*match)(struct device *dev, struct device_driver *drv)
const char *name; ---->匹配成功执行match函数
struct device * dev truct bus_type bus; / type of bus device is on */
const char init_name; / initial name of the device */
void (*release)(struct device *dev);
struct device_driver *drv const struct of_device_id *of_match_table;
const char *name;
struct bus_type bus; / type of bus device is on */
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);

匹配过程描述:

设备和驱动匹配时,需要先导出bus_type的符号EXPORT_SYMBOL(bus_type),设备和驱动端通过extern引用总线名字并填充到结构体信息当中,当设备端和驱动端通过name进行匹配时,只需要将name的信息上传到bus总线上,在总线上进行name的匹配,如果匹配成功则执行dri端的probe函数,probe函数执行后,便可以访问设备端的信息(向下操作硬件),然后再通过fops向上提供接口。

platform总线

https://zhuzhongwei.blog.csdn.net/article/details/92845858

  1. 本质 :platform总线本质上也是基于bus_type的,是在bus_type的基础上做了一层封装
  2. 从这个函数开始看起:platform_driver_register(drv)
  3. platform的bus-dri-dev模型
类型 说明
struct bus_type platform_bus_type .name = “platform”,
.match = platform_match,
static int platform_match(struct device *dev, struct device_driver *drv)
在platform_match中将结构体类型转换为platform的对应类型
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
(of_driver_match_device(dev, drv))设备树匹配
platform_match_id(pdrv->id_table, pdev) != NULL; id_table = id_entry匹配
(strcmp(pdev->name, drv->name) == 0); 名字匹配
struct platform_driver int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *); struct device_driver driver;
const struct of_device_id *of_match_table;
const char *name;
struct bus_type bus; / type of bus device is on */
const struct platform_device_id *id_table;
struct platform_device const char *name;
struct device dev;
struct bus_type bus;/ type of bus device is on */
const char init_name; / initial name of the device */
struct device_node of_node; / associated device tree node */
struct resource *resource;const struct platform_device_id *id_entry;
  • platform的设备匹配原理和bus_type模型一样

IIC总线

从这个函数开始看起:i2c_add_driver(&mpu6050)

IIC分层模型

类型 说明
struct bus_type i2c_bus_type .name = “platform”,
.match = platform_match,
static int platform_match(struct device *dev, struct device_driver *drv)
i2c_device_probe(struct device *dev)
struct i2c_client *client = i2c_verify_client(dev);
struct platform_driver int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
struct device_driver driver;
const struct of_device_id *of_match_table;
const char *name;
struct bus_type bus; / type of bus device is on */
const struct platform_device_id *id_table;
本质 :i2c总线本质上也是基于bus_type的,是在bus_type的基础上做了二层封装
struct platform_device const char *name;
struct device dev;
struct bus_type bus; / type of bus device is on */
const char init_name; / initial name of the device */
struct device_node of_node; / associated device tree node */
struct resource *resource;
const struct platform_device_id *id_entry;
  • platform的设备匹配原理和bus_type模型一样

IIC简单框架搭建

  • IIC读

      char  mpu6050_read(char regaddr){char txbuf[1] = {regaddr};char rxbuf[1] = {0};struct i2c_msg  msgs[2] = {{mpu_client->addr,0,1,txbuf},{mpu_client->addr,1,1,rxbuf}};i2c_transfer(mpu_client->adapter,msgs,2);return rxbuf[0];}
    
  • IIC写

     int  mpu6050_write(char reg,char val){char  txbuf[] ={reg,val};struct i2c_msg  msgs[] = {{mpu_client->addr,0,2,txbuf},};i2c_transfer(mpu_client->adapter,msgs,1);return  0;}
    
  • 框架示意图

  • IIC的读写流程
    IIC读写操作:
    读操作: 从从设备的指定寄存器中读取len个字节的数据放入到buf当中
    mpu6050_i2c_read(uint8 slave_addr,uint8 reg_addr,int len,uint8 buf[])
    IIC初始化 发送start信号 -> (写)发送从机地址 + 0(写)—>等待ACK信号—> 发送从机寄存器地址(8位)–
    ----->等待应答信号ACK—>再次产生起始信号start(开始读数据) —>(读)发送从机地址 + 1(读) +读数据到到buf(连续接受len个长度的数据到buf[i]中 /等ACK)按字节从以reg开头的连续的地址中读取 -->发送NACK信号给从机MPU6050–>结束信号

    写操作: 从buf中读取len个长度的数据写入到从设备指定的寄存器中
    mpu6050_i2c_write(uint8 slave_addr,uint8 reg_addr,int len,uint8 buf[])
    IIC初始化 发送start信号 -> (写)发送从机地址 + 0(写)—>等待ACK信号—> 发送从机寄存器地址(8位)–
    ----->开始写数据(遍历数组,按字节发送 (写),等待应答)按字节写入到以reg开头的连续的地址中去 -->结束信号

看透IIC设备的本质:

IIC总线进行设备和驱动的匹配 字符设备向上层提供过口

输入子系统

https://blog.csdn.net/Set_Mode/article/details/93374846
https://blog.csdn.net/Set_Mode/article/details/93748334

设备树

https://blog.csdn.net/Set_Mode/article/details/93902222

创客学院知识巩固-07驱动初级小结相关推荐

  1. 创客学院知识巩固-06系统移植部分小结

    文章目录 知识框图 uboot与kernel启动与移植流程分析---MAKEFILE Makefile uboot启动流程分析 启动流程 启动分析 uboot移植 内核启动流程分析 内核启动流程 内核 ...

  2. 创客学院知识巩固-01C语言回顾

    文章目录 知识框图 知识框图

  3. 创客学院知识巩固-02数据结构

    文章目录

  4. 创客学院知识巩固-03IO进程

  5. 创客学院知识巩固-04网络

  6. 创客学院知识巩固-05ARM硬件工作原理

  7. 创客学院嵌入式驱动开发——学习资料汇总

    总结  1.创客学院知识巩固-01C语言回顾_C/C++_Set_Mode的博客-CSDN博客 https://blog.csdn.net/Set_Mode/article/details/94431 ...

  8. 《创客学院嵌入式从入门到精通》笔记--10全面掌握嵌入式系统移植

    目录 01嵌入式基本概念,嵌入式开发环境搭建,目标机搭建,TFTP服务搭建,NFS服务搭建 1.系统移植概述及环境搭建 1.通用嵌入式系统软件组成部分 2.Linux 在嵌入式中应用的条件与前景 3. ...

  9. linux驱动之一、LED驱动(驱动代码小结附:github代码链接)

    文章目录 一.相关知识点(涉及接口.结构体.调用关系等) 1.1 裸机开发步骤与驱动开发过程对比 1.1.1 裸机开发步骤 1.1.2 Linux系统下LED驱动开发步骤 1.2 预备知识:写驱动时涉 ...

最新文章

  1. 饭卡(HDOJ2546)
  2. 博客园在升级的路上,不妨更自信些,同时说说我们可以为博客园做些什么
  3. SCA (Service Component Architecture)
  4. java并查集找朋友圈_图—并查集(解决朋友圈问题)
  5. 树莓派摄像头_Arducam 8MP重磅来袭,为树莓派4B构建完全同步的双摄像头方案~
  6. java excel 注解_Java注解--实现简单读取excel
  7. cnpm : 无法加载文件_DELL 服务器R230 加载阵列卡驱动安装Server 2012R2操作系统
  8. 华为vrrp默认优先级_华为VRRP综合配置
  9. 陕西师范大学计算机学院范虹,周素芳 -计算机与信息工程学院官网
  10. 11款程序员实用工具,老少皆宜,你一定用得上!
  11. 王者荣耀在android目录下的名字,王者荣耀手q区有哪些 王者荣耀安卓手Q区名称...
  12. verilog呼吸灯
  13. 基于MT5的沪深股票回测四--回测
  14. .php on line 0,PHP Fatal error: Could not queue new timer in Unknown on line 0
  15. python二级准备一个月能行吗_计算机二级选哪个?一个多月的准备时间够吗?
  16. 【ZZULIOJ】 Python 1016: 银行利率
  17. mac 上开发常用的软件强烈推荐
  18. 浅谈H5业务场景下的人脸识别
  19. 为何需要设置静态工作点?
  20. can分析仪、usb接口can卡的的型号定义

热门文章

  1. windows蓝屏错误代码查询
  2. 微信小程序——圆形图片image控件、两个字和三个字对齐
  3. 1-1 爬取搜狗搜索首页的页面源代码
  4. 通过线程ID获得窗口句柄的方法
  5. 菜鸟学Linux命令:nohup命令启动程序
  6. 牛B的人到处都是(打击的一沓糊涂)
  7. IOC和AOP的面试题
  8. 域控无法同步OUTLOOK提示“该姓名与地址列表中的的姓名不匹配”
  9. 如来十三掌(与佛论禅、Rot13编码)
  10. A Comprehensive Real-World Dataset for Unsupervised Anomaly Detection(翻译)