历史上的今天
今天是:2025年10月13日(星期一)
2022年10月13日 | mini2440 按键驱动POLL机制实验
2022-10-13 来源:csdn
Makefile
KERN_DIR = /home/grh/kernel_source_code/linux-2.6.32.2
all :
make -C $(KERN_DIR) M=`pwd` modules
arm-linux-gcc key_interrupt_app.c -o key_interrupt_app
clean :
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += test_driver.o
obj-m += key_poll.o
obj-m += key_interrupt.o
copy :
cp key_interrupt.ko key_interrupt_app /nfs
驱动源代码,就只是添加了Poll相关的部分
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GRH_MODULE_NAME "key_interrupt" static int major; static struct class *key_interrupt_class; static struct class_device *key_interrupt_device; static int key_value; //wait_event_interruptible函数需要的两个变量 static DECLARE_WAIT_QUEUE_HEAD(grh_wait_interrupt); //休眠的进程队列头 static volatile int sleep_for_interrupt; //这个变量为0的时候read函数会休眠,中断里面将其置1,read函数末尾将其设置为0 //pin_desc是对每一个按键中断的描述,不仅仅可以是整数,也可以是更复杂到的字段,这里用简单的按键值就行了 int pin_desc[6] = { 1, 2, 3, 4, 5, 6 }; //中断处理函数 static irqreturn_t grh_handle_key_eint(int irq, void *dev_id){ int *p; p = dev_id; //printk(KERN_EMERG"key pressed! key=%dn", *p); key_value = *p; //唤醒休眠的进程 sleep_for_interrupt = 1; wake_up_interruptible(&grh_wait_interrupt); return IRQ_HANDLED; } static void init_key(void){ //注册irq中断处理函数,将按键值和中断号绑定,所有清中断操作以及初始化中断相关寄存器的操作全部交给 //内核自动完成了,不再需要像裸机程序一样显式地对寄存器进行读写了,中断发生后会自动跳到grh_handle_key_eint request_irq(IRQ_EINT8, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key1", pin_desc); request_irq(IRQ_EINT11, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key2", pin_desc+1); request_irq(IRQ_EINT13, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key3", pin_desc+2); request_irq(IRQ_EINT14, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key4", pin_desc+3); request_irq(IRQ_EINT15, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key5", pin_desc+4); request_irq(IRQ_EINT19, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key6", pin_desc+5); } static int key_interrupt_open(struct inode *inode, struct file *file){ printk(KERN_EMERG"DRIVER: OPENn"); sleep_for_interrupt = 0; init_key(); return 0; } static ssize_t key_interrupt_write(struct inode *inode, const char __user *buf, size_t count, loff_t *ppos){ printk(KERN_EMERG"DRIVER: WRITEn"); return 0; } static ssize_t key_interrupt_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ printk(KERN_EMERG"DRIVER: READn"); //根据sleep_for_interrupt的数值决定是否将驱动进程加进休眠队列grh_wait_interrupt中,立即休眠进程 wait_event_interruptible(grh_wait_interrupt, sleep_for_interrupt); copy_to_user(buf, &key_value, 4); //下一次进入read的时候继续休眠等待中断发生 sleep_for_interrupt = 0; return 0; } int key_interrupt_release(struct inode *inode, struct file *file){ //注销中断 free_irq(IRQ_EINT8, pin_desc); free_irq(IRQ_EINT11, pin_desc+1); free_irq(IRQ_EINT13, pin_desc+2); free_irq(IRQ_EINT14, pin_desc+3); free_irq(IRQ_EINT15, pin_desc+4); free_irq(IRQ_EINT19, pin_desc+5); printk(KERN_EMERG"DRIVER: RELEASEn"); return 0; } //sys_poll会反复在死循环里面调用key_interrupt_poll unsigned int key_interrupt_poll(struct file *file, struct poll_table_struct *wait){ unsigned int mask; printk(KERN_EMERG"DRIVER POLLn"); poll_wait(file, &grh_wait_interrupt, wait); //把当前进程挂到休眠队列里面,但是不立即休眠 mask = 0; if(sleep_for_interrupt){ //中断发生了 mask |= POLLIN | POLLRDNORM; //把有可读数据的标志位设置为1,用户层可以得到这个mask } return mask; /* 如果返回的mask是0那么进程直接进入定时休眠,如果在定时休眠过程中中断发生了,sys_poll里面的 定时休眠结束,sys_poll又会循环调用key_interrupt_poll,但这个时候mask一定返回非零数值了,这时 sys_poll中的休眠结束,进程继续运行。如果定时休眠过程中中断一直没有发生,那么定时休眠超时之后, sys_poll再调用一次key_interrupt_poll,然会判断是否超时,如果超时直接结束进程的休眠。这是 Linux内核的poll机制的大概原理,这样在用户层调用一次poll函数,进程最多休眠时间就是传进来的wait参数, 中断一发生,定时休眠立刻结束,否则进程就休眠到一次定时休眠结束为止。 */ } static struct file_operations key_interrupt_fops = { .owner = THIS_MODULE, .open = key_interrupt_open, .write = key_interrupt_write, .read = key_interrupt_read, .release = key_interrupt_release, .poll = key_interrupt_poll }; int key_interrupt_module_init(void){ printk(KERN_EMERG"INIT MODULE!n"); //register the driver with the device major = register_chrdev(0, GRH_MODULE_NAME, &key_interrupt_fops); //create my own device class key_interrupt_class = class_create(THIS_MODULE, "key_interrupt_class"); //create my device of my own class key_interrupt_device = device_create(key_interrupt_class, NULL, MKDEV(major,0), NULL, "key_interrupt_device"); return 0; } void key_interrupt_module_exit(void){ unregister_chrdev(major, GRH_MODULE_NAME); device_unregister(key_interrupt_device); class_destroy(key_interrupt_class); printk(KERN_EMERG"EXIT MODULE!n"); } module_init(key_interrupt_module_init); module_exit(key_interrupt_module_exit); MODULE_AUTHOR("GRH"); MODULE_VERSION("1.0"); MODULE_DESCRIPTION("KEY POLL DRIVER"); MODULE_LICENSE("GPL"); 用户空间测试程序,每次在Poll之后判断是不是发生了中断,如果发生了中断就打印按键值,如果超时了就直接退出程序 #include #include #include #include #include #include #include int main(void){ struct pollfd fds[1]; int i, sum, ret; int key_value; int fd; fd = open("/dev/key_interrupt_device", O_RDWR); if(-1 == fd){ printf("open key device error!n"); return -1; } fds[0].fd = fd; fds[0].events = POLLIN; while(1){ ret = poll(fds, 1, 5000); //只监控一个设备,这里不使用poll的多路复用功能,休眠延时是5000ms if(-1 == ret){ printf("poll error!n"); break; } else if(0 == ret){ printf("poll time out!n"); break; } else{ //读操作结束的时候自然驱动程序里面的中断发生的标志sleep_for_interrupt //就清空了,实际上read的时候该标志比为1,进程已经不可能进入休眠了,因为poll //返回正值的时候,才会进入read read(fd, &key_value, 4); printf("key pressed : %dn", key_value); } } close(fd); return 0; } 测试结果(经过测试在timeout情况下,驱动里面poll会调用两次,这和Linux内核中poll机制的实现是吻合的,内核里面实现Poll机制的源代码这里就不分析了,有兴趣的自己去读一下吧,这里只是我自己对实验代码做一个记录而已):
史海拾趣
|
初学Zigbee(MiWi),有前辈给指点下如何快速上手不? -Micrchip MiWi solution. -Demo board都有了 -相关文档也看了不少,总觉得比较浅,望有经验的前辈指点下接下来怎样更全面的学习… 查看全部问答> |
|
一个采集音频信号并且输出波形的小程序。 在EVC中的模拟器下可以看到比较好的效果,无信号时的零线平滑笔直。 下载到板子上,再运行程序,就会发现零线是一条小锯齿的形状,通过一条音频线将PC与ARM相连,短路相接也还是有锯齿。。。 问问大虾这 ...… 查看全部问答> |
|
以下是源码,我想弄清楚unsigned long GetCurTick(void)返回的值有什么用,是不是一个OS的计数值,与系统的时钟有关。 static unsigned long curTimer; static unsigned long TimeOutIni=5400; unsigned long GetCurTick(void) { unsigned lo ...… 查看全部问答> |
|
新手求救:谁有2407扩展cy7c1021cv33 RAM的电路图 我想扩展一片64Kcy7c1021cv33的RAM作调试程序用,谁有这方面的电路图?主要是不知道该把接DS,还PS。 谢谢 brettwkl@163.com… 查看全部问答> |
|
为感谢论坛再次提供开发板的团购机会,我整理一下相关资料,都是网上转来的,方便大家查找, 本人很喜欢这款开发板,虽然可能又要上课抢购不了了~但还是支持这个活动 一,套件清单及硬件资源 二,相关技术资料 ...… 查看全部问答> |
|
在原理图上,你分得清NMOS和PMOS不?说实话用过分立的MOS么?你知道的MOS管的参数又有哪些呢?这个在PC上很常见哦原理图对不对呢?… 查看全部问答> |
|
lm3s系列的内部资源已经学完(但不很熟练),现在是否上系统啊 lm3s系列的内部资源已经学完(但不很熟练),现在是否上系统啊 ,上什么系统 ,,请各位 指点。。 现在大部分人都在弄linux , 像UC一类的 还有前途不?请各位解答… 查看全部问答> |




