驱动开发——IO模型

一、非阻塞IO

1、概念

        在应用程序读取硬件数据时,不管硬件数据有没有准备好,应用程序中的read()函数都不会阻塞,程序继续往下执行

****************应用程序*****************
fd=open("/dev/mycdev",O_RDWR|O_NONBLOCK);
read(fd,buf,sizeof(buf));
**************驱动********************
mycdev_read(struct file*file,ubuf,size,lof)
{
   
    if(file->f_flags&O_NONBLOCK)
    {
        //当前是非阻塞
        //直接读取硬件寄存器的数据
        //  copy_to_user();   
    }
}

二、阻塞IO

1、概念

        在应用程序读取硬件数据时,如果硬件数据有没有准备好,应用程序中的read()函数会阻塞,进程进入休眠态,阻塞等待硬件数据就绪

2、原理

        应用程序中的read()函数会调用驱动中的mycdev_read()函数,存在一个标志变量,在驱动对应的函数中判断其真假。为真则表示硬件数据准备好,直接拷贝数据到用户空间;如果为假,则将进程的task_struct添加到等待队列,将进程切换为(可中断/不可中断)休眠状态。

1.定义等待队列头
wait_queue_head_t wq_head;
2.初始化等待队列头
init_waitqueue_head(&wq_head);
3.wait_event(wq_head, condition)  
功能:检查condition的真假,如果为真,则函数执行结束,如果为假,将进程切换到不可中断休眠状态
参数:wq_head:等待队列头
    condition:标志变量
4.wait_event_interruptible(wq_head, condition) 
   功能:检查condition的真假,如果为真,则函数执行结束,如果为假,将进程切换到可中断休眠状态
参数:wq_head:等待队列头
    condition:标志变量
返回值:如果condition为真则返回0,如果被一个信号中断,则返回错误码-ERESTARTSYS 

5.wake_up(&wq_head)
功能:将不可中断休眠态的进程唤醒,当执行这个函数时如果condition为假,则进程被唤醒后会再次休眠
参数:等待队列头地址
6.wake_up_interruptible(&wq_head)
功能:将  可中断休眠态的进程唤醒当执行这个函数时如果condition为假,则进程被唤醒后会再次休眠
参数:等待队列头地址

三、IO多路复用

1、概念

        想要在一个进程下同时监听多个硬件数据,就需要使用IO多路复用(select、poll、epoll)。

        主要是:在应用程序中将需要监听的事件的文件描述符放入事件集合中,调用函数判断集合中的文件描述符对应的硬件数据是否准备就绪,如果没有事件发生,将进程切换到休眠状态。当有一个或者多个硬件数据准备好了,将休眠的进程唤醒,对准备好的硬件数据进行读写。

2、select-API

************用户空间************
int fd1,fd2;
fd1=open("/dev/mycdev0",O_RDWR);
if(fd1<0)
{
    printf("设备文件打开失败\n");
}
fd2=open("/dev/input/mouse0",O_RDWR);
if(fd2<0)
{
    printf("设备文件打开失败\n");
}
//定义可读集合
 fd_set readfds;
 while(1)
 {
 //清空集合
     FD_ZERO(&readfds);
 //将监听的事件文件描述符添加到可读集合
     FD_SET(fd1,&readfds);
     FD_SET(fd2,&readfds);
     select(fd2+1,&readfds)
     //当select停止阻塞,判断发生的事件并且去读取数据
     if(FD_ISSET(fd1,&readfds))
     {
         read(fd1,buf,sizeof(buf));     
     }
       if(FD_ISSET(fd2,&readfds))
     {
         read(fd2,buf,sizeof(buf));     
     }
 }
 close(fd1);
 close(fd2);

 *************设备驱动层****************
 //select/poll/epoll在设备驱动中的操作方法只有一个,就是下面的这个poll方法
     __poll_t (*poll) (struct file *file, struct poll_table_struct *wait)
     {
         //将等待队列头向上提交
         void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
         {
             功能:向上提交等待队列头
             参数:
                 filp: 文件结构体指针
                 wait_address:要提交的等待队列头首地址
                 p: 将队列头向上提交的通道 
         }
            if(condition)
                return POLLIN;//POLLIN表示发生的事件为读事件POLLOUT表示写事件
            else
                return 0;                  
     }

3、epoll-API

  #include <sys/epoll.h>
   1.int epoll_create(int size);
   功能:创建一个新的epoll
   参数:
       size:大于0的整数
   返回值:成功返回用于操作epoll的文件描述符,失败返回错误码
   2.int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
   功能:进行epoll管理
   参数:
       epfd:epoll_create生成的文件描述符
       op:管理的类型选项
            EPOLL_CTL_ADD:用于在epoll上添加文件描述符
            EPOLL_CTL_MOD:用于修改文件描述符事件类型
            EPOLL_CTL_DEL:从epoll上移除指定的文件描述符
       fd:要操作的文件描述符
       event:设置文件描述符属性的变量
           struct epoll_event {
               uint32_t     events;      /* Epoll events */
                       //EPOLLIN:读
                       //EPOLLOUT:写
               epoll_data_t data;        /* User data variable */
           };
            typedef union epoll_data {
               void        *ptr;
               int          fd;《=======使用这个
               uint32_t     u32;
               uint64_t     u64;
           } epoll_data_t;
返回值:  成功返回0,失败返回错误码                    
   3.int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);
功能:阻塞等待事件发生
参数:
   epfd:epoll_create生成的文件描述符
   events: 存放发生的事件的文件描述符数组的首地址
   maxevents:监听的文件描述符最大个数
   timeout:设置超时事件   毫秒级   -1表示不关注超时 >0超时事件
返回值:
    >0:发生事件的文件描述符个数
    ==0:超时时间到达
    <0:失败

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值