zoukankan      html  css  js  c++  java
  • 第4课.poll机制

    1.poll的简介

    允许进程决定是否可对一个或多个打开的文件做非阻塞的读取或写入。它们常常用于那些要使用多个输入或输出流而又不会阻塞其中任何一个流的应用中

    	unsigned int (*poll) (struct file *, struct poll_table_struct *);
    1.在一个或多个可指示poll状态变化的等待队列上调用poll_wait。如果当前没有文件描述符可以用来执行I/O,则内核将使进程在传递到该系统调用的所有文件描述符对应的等待队列上等待
    2.返回一个用来描述操作是否可以立即无阻塞执行的位掩码。
    

    2.poll_wait

    通过poll_wait函数,驱动程序向poll_table结构添加一个等待队列
    poll_wait并不是马上休眠,而是将进程加入等待队列,等待schedule_timeout休眠

    static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
    POLLIN        :如果设备可以无阻塞的读取,就设置改位
    POLLRDNORM    :如果“通常”的数据已经就绪,可以读取,就设置该位。一个可读设备返回(POLLIN | POLLRDNORM)
    POLLOUT       :如果设备可以无阻塞的写入,就在返回值中设置该位
    POLLWRNORM    :该位和POLLOUT的意义一样,有时其实就是同一个数字。一个可写的设备将返回(POLLOUT | POLLWRNORM)
    

    3.代码解析

    Makefile

    KERN_DIR = /work/system/linux-2.6.22.6
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
    
    obj-m	+= forth_drv.o
    

    fourth_drv.c

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/irq.h>
    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    #include <asm/arch/regs-gpio.h>
    #include <asm/hardware.h>
    #include <linux/poll.h>
    
    
    static struct class *forthdrv_class;
    static struct class_device	*forthdrv_class_dev;
    
    volatile unsigned long *gpfcon;
    volatile unsigned long *gpfdat;
    
    volatile unsigned long *gpgcon;
    volatile unsigned long *gpgdat;
    
    
    static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
    
    /* 中断事件标志, 中断服务程序将它置1,forth_drv_read将它清0 */
    static volatile int ev_press = 0;
    
    
    struct pin_desc{
    	unsigned int pin;
    	unsigned int key_val;
    };
    
    
    /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
    /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
    static unsigned char key_val;
    
    struct pin_desc pins_desc[4] = {
    	{S3C2410_GPF0, 0x01},
    	{S3C2410_GPF2, 0x02},
    	{S3C2410_GPG3, 0x03},
    	{S3C2410_GPG11, 0x04},
    };
    
    
    /*
      * 确定按键值
      */
    static irqreturn_t buttons_irq(int irq, void *dev_id)
    {
    	struct pin_desc * pindesc = (struct pin_desc *)dev_id;
    	unsigned int pinval;
    	
    	pinval = s3c2410_gpio_getpin(pindesc->pin);
    
    	if (pinval)
    	{
    		/* 松开 */
    		key_val = 0x80 | pindesc->key_val;
    	}
    	else
    	{
    		/* 按下 */
    		key_val = pindesc->key_val;
    	}
    
        ev_press = 1;                  /* 表示中断发生了 */
        wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
    
    	
    	return IRQ_RETVAL(IRQ_HANDLED);
    }
    
    static int forth_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;
    }
    
    ssize_t forth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
    {
    	if (size != 1)
    		return -EINVAL;
    
    	/* 如果没有按键动作, 休眠 */
    	wait_event_interruptible(button_waitq, ev_press);
    
    	/* 如果有按键动作, 返回键值 */
    	copy_to_user(buf, &key_val, 1);
    	ev_press = 0;
    	
    	return 1;
    }
    
    
    int forth_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;
    }
    
    static unsigned forth_drv_poll(struct file *file, poll_table *wait)
    {
    	unsigned int mask = 0;
    	poll_wait(file, &button_waitq, wait); // 不会立即休眠
    
    	if (ev_press)
    		mask |= POLLIN | POLLRDNORM;
    
    	return mask;
    }
    
    
    
    static struct file_operations sencod_drv_fops = {
        .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open    =  forth_drv_open,     
    	.read	 =	forth_drv_read,	   
    	.release =  forth_drv_close,
    	.poll    =  forth_drv_poll,
    };
    
    
    int major;
    static int forth_drv_init(void)
    {
    	major = register_chrdev(0, "forth_drv", &sencod_drv_fops);
    
    	forthdrv_class = class_create(THIS_MODULE, "forth_drv");
    
    	forthdrv_class_dev = class_device_create(forthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
    
    	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    	gpfdat = gpfcon + 1;
    
    	gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    	gpgdat = gpgcon + 1;
    
    	return 0;
    }
    
    static void forth_drv_exit(void)
    {
    	unregister_chrdev(major, "forth_drv");
    	class_device_unregister(forthdrv_class_dev);
    	class_destroy(forthdrv_class);
    	iounmap(gpfcon);
    	iounmap(gpgcon);
    	return 0;
    }
    
    
    module_init(forth_drv_init);
    
    module_exit(forth_drv_exit);
    
    MODULE_LICENSE("GPL");
    

    fourthdrvtest.c

    #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;
        
        /*    poll可以同时查询多个文件    */
    	struct pollfd fds[1];
    	
    	fd = open("/dev/buttons", O_RDWR);
    	if (fd < 0)
    	{
    		printf("can't open!
    ");
    	}
    
    	fds[0].fd     = fd;
    	fds[0].events = POLLIN;            //期望有数据等待读取
    	while (1)
    	{
            /*    fds:查询的文件
             *    1  :查询一个文件 
             *    5000 : 超时时间
             */
    		ret = poll(fds, 1, 5000);
    		if (ret == 0)
    		{
    			printf("time out
    ");
    		}
    		else
    		{
    			read(fd, &key_val, 1);
    			printf("key_val = 0x%x
    ", key_val);
    		}
    	}
    	
    	return 0;
    }
  • 相关阅读:
    [转]CentOS 修改yum源为国内源
    著名的镜像网站
    [译]LRTHW练习五——更多的变量及输出打印
    CentOS足迹一
    LRTHW笔记二
    线程的创建和运行(未完待续)
    比较当前时间和给定时间大小
    单独管理image
    Java 修改页面排序条件
    Java 如何使用radio button保存值
  • 原文地址:https://www.cnblogs.com/huangdengtao/p/12492232.html
Copyright © 2011-2022 走看看