RT-Thread系统的IO设备管理模块为上层应用提供了一个对设备进行访问的通用抽象接口,而对于下层设备来说则提供了底层设备驱动框架,并通过定义的数据结构对设备信息和底层设备驱动进行管理。从系统整体位置来说I/O设备管理模块相当于底层设备驱动和上层应用之间的一个中间层。

I/O管理模块实现了对设备驱动程序的封装:设备驱动程序的实现与I/O管理模块独立,提高了模块的可移植性。应用程序通过I/O管理模块提供的标准接口访问底层设备,设备驱动程序的升级不会对上层应用产生影响。这种方式使得与设备的硬件操作相关的代码与应用相隔离,双方只需各自关注自己的功能,这降低了代码的复杂性,提高了系统的可靠性。

一、I/O设备管理控制块:在include/rtdef.h中:

typedef struct rt_device *rt_device_t;
/*** Device structure*/
struct rt_device
{struct rt_object          parent;                   /**< inherit from rt_object *///内核对象enum rt_device_class_type type;                     /**< device type */           //IO设备类型rt_uint16_t               flag;                     /**< device flag */           //设备标志rt_uint16_t               open_flag;                /**< device open flag */      //设备打开标志  rt_uint8_t                ref_count;                /**< reference count */       //打开计数值。设备注册时初始为0,每打开一次加1,每关闭一次减1。主要用于设备多次打开后,要关闭时判断是否完全关闭。rt_uint8_t                device_id;                /**< 0 - 255 */               //设备ID /* device call back */rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);                         //数据接收回调函数  rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);                           //数据发送完回调函数  /* common device interface */rt_err_t  (*init)   (rt_device_t dev);                                            //初始化通用接口  rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);                         //打开通用接口rt_err_t  (*close)  (rt_device_t dev);                                            //关闭通用接口  rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);//读设备通用接口rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);//写设备通用接口rt_err_t  (*control)(rt_device_t dev, rt_uint8_t cmd, void *args);                //控制通用接口void                     *user_data;                /**< device private data */   //私有数据
};在以前版本的设备控制块中,还有以下:
/* 用于支持电源管理的函数接口 */
#ifdef RT_USING_DEVICE_SUSPEND  rt_err_t (*suspend) (rt_device_t dev);                                             //挂起设备  rt_err_t (*resumed) (rt_device_t dev);                                             //还原设备
#endif

从设备控制块,我们可以看到,每个设备对象都会在内核中维护一个设备控制块结构,这种结构是使设备对象继承rt_object基类,然后形成rt_device设备类型。

其中设备类型type为一枚举变量,在include/rtdef.h中定义:

/*** device (I/O) class type*/
enum rt_device_class_type
{RT_Device_Class_Char = 0,                           /**< character device */    //字符设备RT_Device_Class_Block,                              /**< block device */        //块设备RT_Device_Class_NetIf,                              /**< net interface */       //网络设备RT_Device_Class_MTD,                                /**< memory device */       //内存设备RT_Device_Class_CAN,                                /**< CAN device */          //CAN设备RT_Device_Class_RTC,                                /**< RTC device */          //RTC设备RT_Device_Class_Sound,                              /**< Sound device */        //音频设备RT_Device_Class_Graphic,                            /**< Graphic device */      //图形显示设备RT_Device_Class_I2CBUS,                             /**< I2C bus device */      //I2C总线设备RT_Device_Class_USBDevice,                          /**< USB slave device */    //USB从设备RT_Device_Class_USBHost,                            /**< USB host bus */        //USB主设备RT_Device_Class_SPIBUS,                             /**< SPI bus device */      //SPI总线设备RT_Device_Class_SPIDevice,                          /**< SPI device */          //SPI接口设备RT_Device_Class_SDIO,                               /**< SDIO bus device */     //SDIO总线设备RT_Device_Class_PM,                                 /**< PM pseudo device */    //电源管理伪设备RT_Device_Class_Pipe,                               /**< Pipe device */         //管道设备RT_Device_Class_Portal,                             /**< Portal device */       //传输设备RT_Device_Class_Miscellaneous,                      /**< Miscellaneous device *///其他设备RT_Device_Class_Unknown                             /**< unknown device */      //未知设备
};

二、I/O设备管理函数接口:在src/device.c中

注册设备:
rt_err_t rt_device_register(rt_device_t dev,               //设备句柄const char *name,              //设备名称rt_uint16_t flags);            //设备标志
一个设备能够被上层应用访问前,需要先把这个设备注册到系统中,并添加一些相应的属性。这些注册的设备均可以通过设备名,采用“查找设备口”的方式来查找,从而获得该设备控制块(或设备句柄)。
flags参数支持下列参数(可以采用或的方式支持多种参数):
#define RT_DEVICE_FLAG_DEACTIVATE       0x000           /**< device is not not initialized *///未初始化设备
#define RT_DEVICE_FLAG_RDONLY           0x001           /**< read only */                    //只读设备
#define RT_DEVICE_FLAG_WRONLY           0x002           /**< write only */                   //只写设备
#define RT_DEVICE_FLAG_RDWR             0x003           /**< read and write */               //读写设备
#define RT_DEVICE_FLAG_REMOVABLE        0x004           /**< removable device */             //可移除设备
#define RT_DEVICE_FLAG_STANDALONE       0x008           /**< standalone device */            //独立设备
#define RT_DEVICE_FLAG_ACTIVATED        0x010           /**< device is activated */          //已激活设备
#define RT_DEVICE_FLAG_SUSPENDED        0x020           /**< device is suspended */          //挂起设备
#define RT_DEVICE_FLAG_STREAM           0x040           /**< stream mode */                  //设备处于流模式
#define RT_DEVICE_FLAG_INT_RX           0x100           /**< INT mode on Rx */               //设备处于中断接收模式
#define RT_DEVICE_FLAG_DMA_RX           0x200           /**< DMA mode on Rx */               //设备处于DMA接收模式
#define RT_DEVICE_FLAG_INT_TX           0x400           /**< INT mode on Tx */               //设备处于中断发送模式
#define RT_DEVICE_FLAG_DMA_TX           0x800           /**< DMA mode on Tx */               //设备处于DMA发送模式
设备流模式RT_DEVICE_FLAG_STREAM参数用于向串口终端输出字符串:当输出的字符是“\n”时,自动在前面补一个“\r”做分行。警告:应当避免重复注册已经注册的设备,以及注册已有名字的设备驱动程序。卸载设备:
rt_err_t rt_device_unregister(rt_device_t dev);
将设备从设备系统中卸载,被卸载的设备将不能再通过“查找设备接口”被查找到。注:卸载设备并不会释放设备控制块所占用的内存。

初始化所有设备: rt_err_t rt_device_init_all(void); 初始化所有注册到设备对象管理器中的未初始化的设备。注:自版本1.2.x,该函数不再需要在系统初始化调用,因为在上层应用中打开设备时会进行相应设备初始化。 初始化设备: rt_err_t rt_device_init(rt_device_t dev); 当一个设备初始化完成后它的flags域中的RT_DEVICE_FLAG_ACTIVATED应该被置位。如果设备的flags域已经是RT_DEVICE_FLAG_ACTIVATED,调用这个接口将不再重复做初始化。返回dev->init函数返回值RT_EOK。 注:在设备打开时rt_device_open时会调用该函数先初始化需要打开的设备。

查找设备:
rt_device_t rt_device_find(const char *name);
使用这个函数接口时,系统会在设备对象类型所对应的对象容器中根据设备名称遍历寻找设备对象,然后返回该设备句柄,如果没有找到相应的设备对象,则返回RT_NULL。
打开设备:
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag);
根据设备控制块来打开设备,其中访问模式oflags支持以下列表中的参数:
#define RT_DEVICE_OFLAG_CLOSE           0x000           /**< device is closed */ //已关闭模式
#define RT_DEVICE_OFLAG_RDONLY          0x001           /**< read only access */ //只读模式访问
#define RT_DEVICE_OFLAG_WRONLY          0x002           /**< write only access *///只写模式访问
#define RT_DEVICE_OFLAG_RDWR            0x003           /**< read and write */   //读写模式访问
#define RT_DEVICE_OFLAG_OPEN            0x008           /**< device is opened */ //已打开模式
返回dev->open函数返回值。注: 如果设备flags域包含RT_DEVICE_FLAG_STANDALONE参数,将不允许重复打开。关闭设备:
rt_err_t rt_device_close(rt_device_t dev);
根据设备控制块来关闭设备。返回dev->close函数返回值。
读设备:
rt_size_t rt_device_read(rt_device_t dev,                     //设备句柄rt_off_t    pos,                     //待读取数据的偏移量void       *buffer,                  //读取的数据存放地址rt_size_t   size)                    //读取数据的大小
根据设备控制块来读取设备。根据底层驱动的实现,通常这个接口并不会阻塞上层应用线程。
返回读到数据的实际大小(以字节为单位);如果返回0,则需要读取当前线程的errno来判断错误状态。写设备:
rt_size_t rt_device_write(rt_device_t dev,                     //设备句柄rt_off_t    pos,                     //待写入数据的存放偏移量const void *buffer,                  //待写入数据源地址rt_size_t   size)                    //待写入数据大小
根据设备控制块来写入设备。根据底层驱动的实现,通常这个接口也不会阻塞上层应用线程。
返回写入数据的实际大小(以字节为单位);如果返回0,则需要读取当前线程的errno来判断错误状态。注: 在RT-Thread的块设备中,从1.0.0版本开始,rt_device_read()和rt_device_write()接口的pos、size参数按照以块为单位。0.3.x以前的版本则按字节为单位。
控制设备:
rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void *arg);
dev:设备句柄
cmd:命令控制字,这个参数通常与设备驱动程序相关
arg:控制的参数
返回dev->control函数返回值。设置数据接收指示回调函数:
rt_err_t rt_device_set_rx_indicate(rt_device_t dev,      //设备句柄 rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size))//接收回调函数
设置一个回调函数,当硬件设备收到数据时回调以通知用程序有数据到达,但一般只是进行些简单的操作,如释放信号量,而让另一个接收线程来处理接收到的数据
在调用这个函数时,回调函数rx_ind由调用者提供。当硬件设备接收到数据时,会回调这个函数并把收到的数据长度放在size参数中传递给上层应用。上层应用线程应在收到指示后,立刻从设备中读取数据。返回RT_EOK。设置发送完成指示回调函数:
rt_err_trt_device_set_tx_complete(rt_device_t dev,     //设备句柄 rt_err_t (*tx_done)(rt_device_t dev, void *buffer))//发送回调函数
在上层应用调用rt_device_write写入数据时,如果底层硬件能够支持自动发送,那么上层应用可以设置一个回调函数。这个回调函数会在底层硬件给出的发送完成后(例如DMA传送完成或FIFO已经写入完毕产生完成中断时)被调用。
调用这个函数时,回调函数tx_done参数由调用者提供,当硬件设备发送完数据时,由驱动程序回调这个函数并把发送完成的数据块地址buffer做为参数传递给上层应用。上层应用(线程)在收到指示时应根据发送buffer的情况,释放buffer内存块或将其做为下一个写数据的缓存。返回RT_EOK。

三、设备底层驱动实现:

这些驱动实现的底层接口是上层应用最终访问的落脚点,例如上层应用调用rt_device_read接口进行设备读取数据操作,上层应先调用rt_device_find获得相对应的设备句柄,而在调用rt_device_read时,就是使用这个设备句柄所对应驱动的driver_read。上述的接口是一一对应关系。I/O设备模块提供的这六个接口(rt_device_init/open/read/write/control),对应到设备驱动程序的六个接口(driver_init/open/read/write/control等),可以认为是底层设备驱动必须提供的接口。

init:设备初始化。设备初始化后,设备控制块的flag会被置成激活状态(RT_DEVICE_FLAG_ACTIVATED)。如果设备控制块中的flag标志已经设置成激活状 态,那么再运行初始化接口时,会立刻返回,而不会重新进行初始化。

open:打开设备。有些设备并不是系统一启动就已经打开开始运行或者需要进行数据接收,但如果上层应用还未准备好,设备也不应默认已经使能并开始接收数据。所以建议在写底层驱动程序时,应在调用open接口时才使能设备。

close:关闭设备。建议在打开设备时,设备驱动自行维护一个打开计数,在打开设备时进行+1操作,在关闭设备时进行-1操作, 当计数器变为0时,进行真正的关闭操作。

read:从设备中读取数据。参数pos指出读取数据的偏移量,但是有些设备并不一定需要指定偏移量,例如串口设备,设备驱动应忽略这个参数。而对于块设备来说,pos以及size都是以块设备的 数据块大小做为单位的。这个接口                           返回的 类型是rt_size_t,即读到的字节数或块数目。正常情况下应 该会返回参数中size的数值,如果返回零请设置对应的errno值。

write:向设备中写入数据。参数pos指出写入数据的偏移量。与读操作类似,对于块设备来说,pos以及size都是以块设备的数据块 大小做为单位的。这个接口返回的类型是rt_size_t,即真实写入数据的字节数或块数目。正常情况下应该会返回参数中size的数值,如果返回零请设置对应的errno值。

control:根据不同的cmd命令控制设备。命令往往是由底层各类设备驱动自定义实现。例如参数RT_DEVICE_CTRL_BLK_GETGEOME,意思是获取块设备的大小信息。

底层驱动实现步骤:

• 按照RT-Thread的对象模型,扩展一个对象有两种方式:
  (1)定义自己的私有数据结构,然后赋值到RT-Thread设备控制块的user_data指针上;
  (2)从struct rt_device结构中进行派生。
• 实现RT-Thread I/O设备模块中定义的6个公共设备接口,开始可以是空函数(返回类型是rt_err_t的可默认返回RT_EOK);
• 根据自己的设备类型定义自己的私有数据域。特别是在可能有多个相类似设备的情况下(例如串口1、2),设备接口可以共用同一套接口,不同的只是各自的数据域(例如寄存器基地址);
• 根据设备的类型,注册到RT-Thread设备框架中,即调用rt_device_register接口进行注册。

RT-thread内核之IO设备管理系统相关推荐

  1. Linux内核:IO设备通信的控制方式

    IO设备与主机(CPU.内存)之间的通信不是直接的,而是通过设备控制器,设备控制器是IO设备和主机之间的中介.IO设备和进程之间的数据传送方式主要有4种: 1.程序控制方式:又被称为"忙等& ...

  2. xpt 2046的触摸屏 rt thread设备驱动框架

    1 基于rtt 开发触摸屏驱动 准备使用rtt 框架 , 驱动xpt 2046的触摸屏, 翻阅大量资料发现, 大部分文章强调的是时序图, 而且很多代码要么直接操作寄存器, 要么是io 口模拟, 只能用 ...

  3. 使用RT Thread设备框架封装一个I2C设备——DS3231

    使用RT Thread设备框架封装一个I2C设备--DS3231 前言 ENV配置 I2C测试 将ds3231封装成一个字符设备 结语 前言 学习rt thread的I2C的时候,恰巧手上的板子留了d ...

  4. 报错:Exception in thread “main“ java.io.IOException: 设备未就绪。

    今天用File创建文件,但是一直报错,报错提示设备未就绪,很纳闷 Exception in thread "main" java.io.IOException: 设备未就绪.at ...

  5. 基于GD32F103C8T6添加RT Thread nano设备框架并添加串口设备(以控制台console( uart0 )为例)

    最近没事琢磨了一下使用设备框架的问题.因为将串口注册到设备框架可以应用十分丰富的软件包. 于是就整理了一下手上的工程,重新将工程梳理了一遍. 像这样是十分清爽了,其中RTOS是操作系统源代码 并且学习 ...

  6. rtt面向对象oopc——3.对官方IO设备模型框架图的补充绘图

    该补充图有幸得到rt thread官方认可,gitee上已提交PR,且通过了官方评审,已被合并到<IO设备模型>章节末尾的<补充说明>小节里了rt-thread官方文档gite ...

  7. RTT——IO设备管理篇·基本概念理解

    一.通过对象容器进行管理的, 对象容器就像系统的监控器一样,监控系统,系统咋干嘛都知道,是个全局性得管理系统. 二.内核对象基类派生出设备对象基类,设备对象基类是对对象基类的继承和派生. 具体设备类型 ...

  8. Yeelink平台使用——远程控制 RT Thread + LwIP+ STM32

    1.前言     [2014年4月重写该博文]     经过若干时间的努力终于搞定了STM32+LwIP和yeelink平台的数据互通,在学习的过程中大部分时间花在以太网协议栈学习上,但是在RT Th ...

  9. linux内核中的 哈希表_Linux内核中的设备模型及SCSI示例解析

    关于硬件架构 想要了解Linux操作系统的内核设备和驱动模型,最好先了解一下现在计算机硬件的架构.对计算机硬件有一定了解之后,对理解Linux内核中的设备和驱动模型非常有帮助.如图1是常规计算机的硬件 ...

最新文章

  1. NeurIPS 2019最佳论文出炉,今年增设“新方向奖”,微软华人学者获经典论文奖...
  2. Informix IDS 11体系打点(918考试)认证指南,第 5 局部: 数据库管事器操作(4)
  3. 美术干货:用Blender绘制low poly风格的游戏角色
  4. RHCE-samba服务
  5. 汇编学习笔记(4)-伪指令(MASM)
  6. python histo 改变 bins 大小_在Python中显示具有非常不均匀的bin宽度的直方图
  7. 【java机器学习】决策树算法
  8. C#LeetCode刷题之#455-分发饼干(Assign Cookies)
  9. grid.getSelectionModel的所有操作
  10. 整理了一个目录,督促自己写文章
  11. ajax异步session值不唯一 总是改变 解决办法
  12. Handler+MessageQueue等操作
  13. Java中异常处理示例
  14. L298N 小车应用(附代码)
  15. servlet中使用db4o
  16. java商城的面试题,Java商城系统面试题(一)
  17. 充分利用公网 -- 将联通光猫设置为桥接
  18. 内部软件技术文档怎么做?
  19. cs起源本地服务器无响应,CS起源上为什么我无法进入有反作
  20. react中使用水印water-mark-oc

热门文章

  1. Android开发5年,怎么样通过自学拿到40W年薪的?,安卓面试题最新2020
  2. 如何在GitHub上传并更新项目
  3. 彻底弄懂base64的编码与解码原理
  4. Apache的winnt_accept: Asynchronous AcceptEx failed问题
  5. matlab数学建模方法与实践 笔记1:快速入门
  6. Vue项目清理本地缓存并删除node_modules (清除不掉揍我)
  7. 单证与双证高级证书与普通证书的区别与联系
  8. Java学习(4)—— 布尔类型、基本数据类型转换、基本数据类型和String类型的转换
  9. grub linux修复 pe,恢复Ubuntu GRUB引导的方法
  10. RGB888 和 RGB565