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)实现驱动对设备的操作
           获取硬件资源,实现对设备操作
 

原文地址:https://www.cnblogs.com/wanghuaijun/p/7294038.html