• IO模型


    【1】IO模型
     1)阻塞IO
     2)非阻塞IO
     3)IO多路复用
     4)异步IO
     
    【2】IO多路复用
     多路复用在阻塞IO模型上封装的
     
     应用程序:
            int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
            功能:实现对文件描述符的监听(如果某一个文件描述符准备就绪,select立刻返回)
            函数本身阻塞函数,实现对文件描述符轮询检测

            void FD_CLR(int fd, fd_set *set);  从文件描述符集合中将描述符移除
            int  FD_ISSET(int fd, fd_set *set); 查看当期的文件描述符是否在文件描述符集合中
            void FD_SET(int fd, fd_set *set);  向文件描述符集合中将描述符添加
            void FD_ZERO(fd_set *set);         清空文件描述符集合
            
     驱动:
            unsigned int (*poll) (struct file *, struct poll_table_struct *);
            a)对可能引起设备文件状态变化的等待队列调用poll_wait函数,将对应的等待队列头添加到poll_table
               由内核检测poll_table
               
               static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
               功能:将等待队列加入到poll_table表
               参数:filep
                     wait_address  等待队列头
                     p    poll_table表     
               
            b)返回表示是否能对设备进行无阻塞读,写访问的掩码
                      POLLIN,POLLOUT,POLLRDNORM,POLLERR
                       可读    可写     正常        错误
                       
               return POLLIN|POLLRDNORM
    【3】异步IO
     异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态
     
     应用程序:
        应用程序要捕捉SIGIO信号,注册信号
        signal(SIGIO, handler);  

         应用程序要指定进程为文件的属主
         当前文件描述符属于该进程,进程需要对该文件描述符状态发生改变之后,处理相应的任务
        fcntl(fd, F_SETOWN, getpid());
        
         int fcntl(int fd, int cmd, ... /* arg */ );
         参数:fd  文件描述符
               cmd  定义对文件描述符的操作
               arg  附件参数

        应用程序通过fcntl函数在设备中设置FASYNC标志
        oflags = fcntl(fd, F_GETFL);   获取当前文件描述符的标志位
        fcntl(fd, F_SETFL, oflags | FASYNC); 重新设置标志位

     
       驱动:
           1)支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。不过此项工作已由内核完成,设备驱动无须处理。
           2)支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。因此,驱动中应该实现fasync()函数
               fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
               功能:将文件描述符添加到异步通知队列中
               参数:fd  文件描述符
                     filep  
                     on  打开设备的标志位
                     fapp  异步通知队列       
           3)在设备资源可获得时,调用kill_fasync()函数激发相应的信号
              void kill_fasync(struct fasync_struct **fp, int sig, int band)
              功能:向应用程序发送信号
              参数:fp  异步通知队列
                    sig  发送的信号类型
                    band  掩码  POLLIN可读
                                POLLOUT可写
                                
    【4】Linux驱动中设备模型
     在Linux内核中,将对设备的操作代码抽象成一个对象(驱动)
                    将对设备的硬件描述抽象成一个对象(设备)
                    将该设备使用的总线抽象成一个对象(总线)
     
     在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成
     
     总线可以是物理存在的,也可以是虚拟的。内核中对应的结构为struct bus_type(描述一个总线对象)
       struct bus_type {
              const char        *name; 总线的名称
              int (*match)(struct device *dev, struct device_driver *drv); 实现设备与驱动的匹配
       }
     设备是连接到某条物理或者虚拟总线上的对象。可能是真正物理对象,也可能是虚拟对象。内核中对应的结构为struct device
       struct device{
             struct kobject kobj;  所有的设备对象的父亲
             const char        *init_name;   设备的名称
             struct bus_type    *bus;    总线的名称
             void        *platform_data;    私有数据,存放的是硬件的信息
             void    (*release)(struct device *dev);      卸载设备模块时,自动执行此函数    
       }
     
     驱动是用来和设备通信的软件程序。驱动可以从设备中获取数据,也可以把相应数据发给设备进行处理。内核中对应的结构为struct devicc_driver
       struct device_driver{
            const char        *name;  名称
            struct bus_type        *bus; 总线的名称
            struct module        *owner;  THIS_MODULE
            const struct of_device_id    *of_match_table;  设备树匹配
            int (*probe) (struct device *dev);  回调函数(一但设备与驱动匹配成功,自动执行此函数,存放对设备的操作的代码)
            int (*remove) (struct device *dev); 卸载函数(存放的与probe执行相反的代码)
            
       }
     
     如何实现Linux设备模型:
         1)构建总线对象,并且向内核完成注册
                注册:int bus_register(struct bus_type *bus)
                注销:void bus_unregister(struct bus_type *bus)
         2)构建设备对象,并且向内核完成注册
                注册:int device_register(struct device *dev)  
                注销:void device_unregister(struct device *dev)            
         3)构建驱动对象,并且向内核完成注册
                注册:int driver_register(struct device_driver *drv)
                注销:void driver_unregister(struct device_driver *drv)
         4)实现设备与驱动的匹配
                实现匹配操作
         5)实现驱动对设备的操作    
        
    【5】platform设备模型
     将设备,驱动,总线抽象成一个对象
     
     设备对象:描述硬件信息
         struct platform_device {
               const char    *name;  设备的名称
               struct device    dev;   描述设备对象的结构体
                      void    (*release)(struct device *dev);
               u32        num_resources;   描述硬件资源的数量
               struct resource    *resource;   描述硬件资源的信息
        };
        
        struct resource {
        resource_size_t start;   起始地址
        resource_size_t end;     结束地址
        unsigned long flags      标志-描述地址属性
        };    
        
        #define IORESOURCE_MEM        0x00000200  内存地址
        #define IORESOURCE_REG        0x00000300    寄存器的偏移量
        #define IORESOURCE_IRQ        0x00000400  中断
     
     驱动对象:描述驱动代码
        struct platform_driver {
             int (*probe)(struct platform_device *);    回调函数(一但设备与驱动匹配成功,自动执行此函数,存放对设备的操作的代码)
             int (*remove)(struct platform_device *);   卸载函数(存放的与probe执行相反的代码)
             struct device_driver driver;    描述所有驱动对象的结构体
                    const char        *name;
                    struct module        *owner;  
                    const struct of_device_id    *of_match_table;  实现设备树的匹配
             const struct platform_device_id *id_table;  匹配表
            };
     总线对象:描述总线信息
         struct bus_type platform_bus_type = {
               .name        = "platform",      总线的名称
               .match        = platform_match,  匹配方法
         };
     
     platform平台匹配方法
          static int platform_match(struct device *dev, struct device_driver *drv)
         {
        struct platform_device *pdev = to_platform_device(dev);
        struct platform_driver *pdrv = to_platform_driver(drv);

        /* Attempt an OF style match first */          设备树匹配
        if (of_driver_match_device(dev, drv))
            return 1;
        /* Then try to match against the id table */   匹配表匹配
        if (pdrv->id_table)  
            return platform_match_id(pdrv->id_table, pdev) != NULL;   

        /* fall-back to driver name match */
        return (strcmp(pdev->name, drv->name) == 0);    名字匹配
        }
     
     如何实现platform平台模型:
        1)构建设备对象,并且向内核完成注册
               注册:int platform_device_register(struct platform_device *pdev)
               注销:void platform_device_unregister(struct platform_device *pdev)           
        2)构建驱动对象,并且向内核完成注册
               注册:#define platform_driver_register(drv)   __platform_driver_register(drv, THIS_MODULE)
               注销:platform_driver_unregister(struct platform_driver *);
        3)实现设备与驱动的匹配
               匹配方法已实现
        4)实现驱动对设备的操作
               获取硬件资源,实现对设备操作
     

  • 相关阅读:
    Leetcode 811. Subdomain Visit Count
    Leetcode 70. Climbing Stairs
    Leetcode 509. Fibonacci Number
    Leetcode 771. Jewels and Stones
    Leetcode 217. Contains Duplicate
    MYSQL安装第三步报错
    .net 开发WEB程序
    JDK版本问题
    打开ECLIPSE 报failed to load the jni shared library
    ANSI_NULLS SQL语句
  • 原文地址:https://www.cnblogs.com/wanghuaijun/p/7294038.html
Copyright © 2020-2023  润新知