linux字符设备驱动之poll篇(三)

一 what

poll,顾名思义,就是查询的意思,但是这里的查询,跟我们第一篇中通过在while循环中一直read方式的轮询有什么区别呢?
linux内核提供了poll函数给用户程序查询字符设备的状态,它带有一个超时等待机制,当在规定时间内没有读取到字符设备的状态时,将直接返回,释放掉cpu进入休眠;如果在规定时间内产生了某个中断,我们可以利用read函数去读取字符设备的状态,从本质上来说,poll机制还是利用中断方式来实现的,和上一篇文章中有区别的地方就是,上一篇等待唤醒休眠是在read函数中实现的,而在poll机制中,实在poll函数中实现。
这篇文章也是先以使用内核函数为主,关于内核中的实现细节未做深度分析。

二 why

同样使用中断的原因,也是为避免长时间占用cpu的问题;同时将唤醒动作从read函数中提取出来,使用poll函数来实现。

三 how

a. open函数

static int fourth_drv_open(struct inode *inode, struct file *file)
{
    /* 配置GPF0,2为输出引脚 */
    /* 配置GPG3,11为输出引脚 */
    request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
    request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
    request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
    request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);

    return 0;
}

b. read函数

static int fourth_drv_read(struct file *filp, char __user *buf, 
                                         size_t size, loff_t *ppos)
{
    /* 返回4个引脚电平状态 */
    if (size != 1)
        return -EINVAL;

    /* 如果没有按键动作, 休眠 */
    wait_event_interruptible(button_waitq, ev_press);

    /* 如果有按键动作, 返回键值 */
    copy_to_user(buf, &key_val, 1);
    ev_press = 0;

    return (sizeof(key_val));
}

c. close函数

int fourth_drv_close(struct inode *inode, struct file *file)
{
    free_irq(IRQ_EINT0, &pins_desc[0]);
    free_irq(IRQ_EINT2, &pins_desc[1]);
    free_irq(IRQ_EINT11, &pins_desc[2]);
    free_irq(IRQ_EINT19, &pins_desc[3]);

    return 0;
}

d. poll函数
上面的几个函数和《linux字符设备驱动之中断篇(二)》基本一样,重点分析一下这里的poll函数,它调用了poll_wait函数,第三个参数为超时等待时间

static unsigned int fourth_drv_poll(struct file *file, struct poll_table_struct *wait)
{
    unsigned int mask = 0;

    poll_wait(file, &button_waitq, wait); // 不会立即休眠
    if (ev_press)
        mask |= POLLIN | POLLRDNORM;

	return mask;
}

四 test

  1. 写drvtest用户程序,比如针对按键按下的可执行程序,代码如下
    重点关注struct pollfd fds[1]和ret = poll(fds, 1, 5000)两句;
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>


/* forthdrvtest 
  */
int main(int argc, char **argv)
{
	int fd;
	unsigned char key_val;
	int ret;

	struct pollfd fds[1];
	
	fd = open("/dev/buttons", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
        return 0;
	}

	fds[0].fd     = fd;
	fds[0].events = POLLIN;
	while (1)
	{
		ret = poll(fds, 1, 5000);
		if (ret == 0)
		{
			printf("time out\n");
		}
		else
		{
			read(fd, &key_val, 1);
			printf("key_val = 0x%x\n", key_val);
		}
	}
	
	return 0;
}
  1. 编译动态库: make
  2. 编译用户程序: arm-linux-gcc -0 xxx xxx.c
  3. 上传动态库以及可执行程序到nfs服务器 cp xxx /work/nfs/first_fs
  4. 加载动态库: insmod xxx.ko
  5. 修改可执行文件权限: chmod +777 yyy
  6. 执行可执行程序
    之所以采用中断的实现方式,是为了降低cpu的占用率,我们使用top命令查看此时cpu占用率,发现比一直读取的方法明显降低了许多
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值