当前位置:首页 > CN2资讯 > 正文内容

linux espi驱动 linux 驱动poll

2天前CN2资讯

POLL操作


1、POLL运行过程:

poll是一个系统调用,其内核入口函数为sys_poll,sys_poll差点儿不做不论什么处理直接调用do_sys_poll,do_sys_poll的运行过程能够分为三个部分:

 1,将用户传入的pollfd数组复制到内核空间,由于拷贝操作和数组长度相关。时间上这是一个O(n)操作,这一步的代码在do_sys_poll中包含从函数開始到调用do_poll前的部分。

 2,查询每一个文件描写叙述符相应设备的状态,假设该设备尚未就绪,则在该设备的等待队列中增加一项并继续查询下一设备的状态。

查询全然部设备后假设没有一个设备就绪,这时则须要挂起当前进程等待。直到设备就绪或者超时,挂起操作是通过调用schedule_timeout执行的。设备就绪后进程被通知继续执行,这时再次遍历全部设备,以查找就绪设备。这一步由于两次遍历全部设备。时间复杂度也是O(n),这里面不包含等待时间。相关代码在do_poll函数中。
 3,将获得的数据传送到用户空间并运行释放内存和剥离等待队列等善后工作,向用户空间拷贝数据与剥离等待队列等操作的的时间复杂度相同是O(n),详细代码包含do_sys_poll函数中调用do_poll后到结束的部分。


2、代码编写

1、在file_operations结构体中加入 poll

static struct file_operations button_sdv_fops = { .owner = THIS_MODULE, .open = button_dev_open, .read = button_dev_read, .release = button_dev_close, .poll = button_dev_poll, };


2、完毕 button_dev_poll函数

static unsigned int button_dev_poll(struct file *file, poll_table * wait) { unsigned int mask =0; poll_wait(file, &button_wait_q, wait);//把当前进程挂到队列里面,不会立马休眠 if(ev_press) mask |=POLLIN |POLLRDNORM; return mask; }


当中ev_press是上一篇博文中的中断事件发生标志,假设中断动作发生,则mask值将被告诉内核。当中 mask的值的含义:


常量

说明

POLLIN

普通或优先级带数据可读

POLLRDNORM

普通数据可读

POLLRDBAND

优先级带数据可读

POLLPRI

高优先级数据可读

POLLOUT

普通数据可写

POLLWRNORM

普通数据可写

POLLWRBAND

优先级带数据可写

POLLERR

错误发生

POLLHUP

发生挂起

POLLNVAL

描写叙述字不是一个打开的文件

3、測试程序编写

ret = poll(fds, 1, 3000);

poll函数原型:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

当中:pollfd结构体为:

struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ };

fd是要查询的设备。events是期望获得的事件,这里我们将他设置为:POLLIN

fds定义一个数组,存放须要poll的全部设备。poll操作会同一时候查询这些设备。

nfds为查询的文件数量

timeout为超时时间


驱动程序完整代码:

#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/io.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <mach/regs-gpio.h> #include <mach/irqs.h>//这个在/opt/EmbedSky/linux-2.6.30.4/arch/arm/mach-s3c2410/include/mach 路径 #include <linux/interrupt.h> #include <linux/poll.h> MODULE_LICENSE("Dual BSD/GPL"); static struct class *buttondrv_class; static struct class_devices *buttondrv_class_dev; /* */ static DECLARE_WAIT_QUEUE_HEAD(button_wait_q); /*中断事件标志,中断服务程序将他置1,read函数将他置0*/ static volatile int ev_press =0; volatile unsigned long *gpfcon = NULL; volatile unsigned long *gpfdat = NULL; static unsigned keyval; struct pin_desc{ unsigned int pin; unsigned int key_value; }; /*按键按下时是:0x01 0x02 0x03 0x04*/ /*按键松开时是:0x81 0x82 0x83 0x84*/ struct pin_desc pins_desc[4] = { {S3C2410_GPF1,0x01}, {S3C2410_GPF4,0x02}, {S3C2410_GPF2,0x03}, {S3C2410_GPF0,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)//松开 { keyval = 0x80|pindesc->key_value; } else { keyval = pindesc->key_value; } ev_press =1;//中断发生 wake_up_interruptible(&button_wait_q); printk("button is pressed : %d \n",irq); return IRQ_HANDLED; } static int button_dev_open(struct inode *inode ,struct file* file) { //配置按键的引脚 GPF0,1,2,4为输入引脚 request_irq(IRQ_EINT1,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key1",&pins_desc[0]); request_irq(IRQ_EINT4,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key2",&pins_desc[1]); request_irq(IRQ_EINT2,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key3",&pins_desc[2]); request_irq(IRQ_EINT0,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key4",&pins_desc[3]); return 0; } ssize_t button_dev_read(struct file *file,char __user *buf,size_t size,loff_t *ppos) { if(size !=1) { return -EINVAL; } /*假设没有按键动作发生 就休眠*/ wait_event_interruptible(button_wait_q,ev_press); /*假设有按键动作发生,直接返回*/ copy_to_user(buf,&keyval,1); ev_press = 0; return 0; } int button_dev_close(struct inode* inode ,struct file *file) { free_irq(IRQ_EINT1,&pins_desc[0]); free_irq(IRQ_EINT4,&pins_desc[1]); free_irq(IRQ_EINT2,&pins_desc[2]); free_irq(IRQ_EINT0,&pins_desc[3]); return 0; } static unsigned int button_dev_poll(struct file *file, poll_table * wait) { unsigned int mask =0; poll_wait(file, &button_wait_q, wait);//把当前进程挂到队列里面,不会立马休眠 if(ev_press) mask |=POLLIN |POLLRDNORM; return mask; } static struct file_operations button_sdv_fops = { .owner = THIS_MODULE, .open = button_dev_open, .read = button_dev_read, .release = button_dev_close, .poll = button_dev_poll, }; int major; static int button_dev_init(void)//入口函数 { major = register_chrdev(0,"button_drv",&button_sdv_fops); buttondrv_class = class_create(THIS_MODULE,"button_drv"); if(IS_ERR(buttondrv_class)) return PTR_ERR(buttondrv_class); buttondrv_class_dev= device_create(buttondrv_class,NULL,MKDEV(major,0),NULL,"wq_button"); if(unlikely(IS_ERR(buttondrv_class_dev))) return PTR_ERR(buttondrv_class_dev); /*映射物理地址*/ gpfcon = (volatile unsigned long *) ioremap(0x56000050 ,16); gpfdat = gpfcon + 1; return 0; } static void button_dev_exit(void) { unregister_chrdev(major,"button_drv"); device_unregister(buttondrv_class_dev); class_destroy(buttondrv_class); iounmap(gpfcon); } module_init(button_dev_init); module_exit(button_dev_exit);


測试程序完整代码:

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <poll.h> int main(int argc, char **argv) { int ret=0; int cnt=0; int fd; unsigned char key_val; struct pollfd fds[1]; fd = open("/dev/wq_button", O_RDWR); if(fd<0) { printf("can't open \n"); } fds[0].fd = fd; fds[0].events = POLLIN; while(1) { ret = poll(fds, 1, 3000); if(ret == 0) { printf("time out \n"); } else { read(fd,&key_val,1); printf("key_val = 0x%x\n",key_val); } } return 0; }










    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/25775.html

    分享给朋友:

    “linux espi驱动 linux 驱动poll” 的相关文章

    APT是什么?高级持续性威胁的定义与防御策略

    APT是指高级持续性威胁(Advanced Persistent Threat),它代表了一种针对特定目标进行的长期和有计划的网络攻击。这种攻击的高端特征在于,攻击者会在施加攻击之前,详细调查并了解攻击对象的业务流程和系统架构。换句话说,APT并不是一种简单随机的攻击,而是通过深入分析和细致的侦查工...

    如何优化网络体验:VPS中转全面指南

    我一直对如何使用技术来优化我的网络体验感到好奇。最近,我发现了VPS中转这种神奇的方法。简单来说,VPS中转就是利用一台虚拟私人服务器(VPS),将我的网络流量转发到另一个指定的网络地址。这种功能主要用于加速访问某些海外网站,帮助我突破网络限制以及保护我的上网隐私等。 在日常使用中,我会遇到一些网站...

    提升国际数据传输质量的9929线路分析与应用

    谈到9929线路,首先让我给大家介绍一下AS9929线路的基本情况。这条线路是中国联通为了满足国际市场的需求而推出的一种IP传输服务专线。它的起点在香港,通过海底光缆将中国与亚太及北美地区紧密连接。同时,这条线路还在欧洲和非洲设立了多个重要的网络节点(POP点),这就为跨国数据传输提供了坚实的基础。...

    VPS IP被封怎么办?常见原因与解决方案分析

    在使用VPS的过程中,有时候会遇到VPS IP被封的情况,这对很多用户来说,会带来一些困扰。虽然情况不同,但通常来说,下列几个原因是比较常见的,了解这些原因能够帮助我们更好地避免封禁。 首先,敏感操作常常是导致IP被封的重要原因之一。比如,如果你进行了一些网络爬虫、频繁请求某个网站内容,或者试图访问...

    如何有效优化后重置流量管理以提高客户忠诚度

    后重置流量的基本概念 后重置流量,简单来说,是指在广告或市场推广活动进行重置后,仍旧能够吸引到的用户流量。这种流量的定义不仅涵盖了用户的访问数,还强调了这些用户与品牌的关系。在今天的数字营销环境中,后重置流量逐渐成为了评估广告效果和用户粘性的关键指标之一。 我认识到后重置流量的重要性在于,它不仅能够...

    掌握PVM: 并行虚拟机在高效计算中的应用与优势

    什么是PVM PVM,全称为“并行虚拟机”(Parallel Virtual Machine),是一种软件架构,用于多台计算机之间的并行计算。这种技术使得不同的计算机可以连接在一起,像一个单一的超级计算机一样共同完成任务。想象一下,你在进行一个复杂的计算,它需要大量的时间和资源。通过PVM,你可以将...