【Tiny6410 And Linux】—(2.3)—使用工作队列处理按键中断——代码
2012-05-14 23:07
656 查看
做了做用工作队列处理按键中断的实验,对中断开始明白~~
呵呵~~其实今天就是加了个全局变量(虽然这在驱动程序中不是很合适吧),还有就是加了个消抖(就是通过延时等待而已)!
1、驱动程序
①、plat_btn_dev.c
②、plat_but_drv.c
③、Makefile
2、测试程序
①、app_btn.c
3、测试结果
呵呵~~其实今天就是加了个全局变量(虽然这在驱动程序中不是很合适吧),还有就是加了个消抖(就是通过延时等待而已)!
1、驱动程序
①、plat_btn_dev.c
#include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/device.h> #define DEVICE_NAME "tiny6410_buttons" /* 平台资源的定义 */ static struct resource tiny6410_buttons_resource[] = { [0] = { .start = IRQ_EINT(0), .end = IRQ_EINT(0), .flags = IORESOURCE_IRQ, }, [1] = { .start = IRQ_EINT(1), .end = IRQ_EINT(1), .flags = IORESOURCE_IRQ, }, [2] = { .start = IRQ_EINT(2), .end = IRQ_EINT(2), .flags = IORESOURCE_IRQ, }, [3] = { .start = IRQ_EINT(3), .end = IRQ_EINT(3), .flags = IORESOURCE_IRQ, }, [4] = { .start = IRQ_EINT(4), .end = IRQ_EINT(4), .flags = IORESOURCE_IRQ, }, [5] = { .start = IRQ_EINT(5), .end = IRQ_EINT(5), .flags = IORESOURCE_IRQ, }, [6] = { .start = IRQ_EINT(19), .end = IRQ_EINT(19), .flags = IORESOURCE_IRQ, }, [7] = { .start = IRQ_EINT(20), .end = IRQ_EINT(20), .flags = IORESOURCE_IRQ, } /* 这里不需要加逗号 */ }; static struct platform_device *tiny6410_buttons_dev; static int __init platform_init(void) { printk("[Call platform_init!]\n"); /* 分配一个 platform_device 结构 */ tiny6410_buttons_dev = platform_device_alloc(DEVICE_NAME, -1); /* 为平台设备添加平台设备资源 */ platform_device_add_resources(tiny6410_buttons_dev, tiny6410_buttons_resource, 8); /* 注册平台设备 */ platform_device_add(tiny6410_buttons_dev); return 0; } static void __exit platform_exit(void) { printk("[Call platform_exit!]\n"); platform_device_unregister(tiny6410_buttons_dev); } module_init(platform_init); module_exit(platform_exit); MODULE_AUTHOR("_Justin"); MODULE_LICENSE("GPL");
②、plat_but_drv.c
#include <linux/module.h> #include <linux/types.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/uaccess.h> #include <linux/io.h> #include <mach/map.h> #include <mach/regs-gpio.h> #include <linux/poll.h> #include <linux/irq.h> #include <asm/unistd.h> #include <linux/device.h> #include <linux/workqueue.h> #include <mach/gpio-bank-n.h> #include <mach/gpio-bank-l.h> #define DRIVER_NAME "tiny6410_buttons" #define DEVICE_NAME "tiny6410_buttons" /* 注意: * 在一个较规范的驱动程序中,通常不会将设备资源在平台驱动程序中 * 以全局变量的形式给出(这里是为了简化操作,将部分设备资源以全局变量形式 * 给出),一个更好的办法是,将这些资源都添加到对应的平台设备中,以平台 * 设备资源或者平台设备似有数据的形式管理。 */ /* 记录按键中断号 */ typedef struct { int irq; /* 中断号,初始化为 0,将在 * probe 获取资源 */ int num; /* 对应的按键编号 */ char *name; /* 中断所属的名字 */ } button_irq_t; /* 按键数据结构 */ typedef struct { wait_queue_head_t bwq; /* 按键等待队列 */ struct delayed_work dwork; /* 用于按键中断下半部分的延迟工作 */ button_irq_t *birqs; /* 指向记录按键中断资源数组 */ int nirqs; /* 设备支持的按键中断数 */ int val; /* 记录键值 */ volatile int cnum; /* 记录产生中断的按键编号 */ volatile int press; /* 等待队列条件 */ } buttons_data_t; button_irq_t button_irqs[] = { {0, 0, "KEY0"}, {0, 1, "KEY1"}, {0, 2, "KEY2"}, {0, 3, "KEY3"}, {0, 4, "KEY4"}, {0, 5, "KEY5"}, {0, 6, "KEY6"}, {0, 7, "KEY7"}, }; /* 按键驱动数据全局变量 g_bd */ static buttons_data_t g_bd = { .birqs = button_irqs, .nirqs = sizeof(button_irqs) / sizeof(button_irqs[0]), .press = 0, }; /* * buttons_work_func 函数 * 延迟工作的回调函数则负责完成中断处理程序中未完成的工作 */ static void buttons_work_func(struct work_struct *w) { int down; unsigned tmp; int num = g_bd.cnum; switch(num) { case 0: case 1: case 2: case 3: case 4: case 5: tmp = readl(S3C64XX_GPNDAT); down = !(tmp & (1 << num)); break; case 6: case 7: tmp = readl(S3C64XX_GPLDAT); down = !(tmp & (1 << (num + 5))); break; default: down = 0; } if(down == !(g_bd.val & (1 << num))) { g_bd.val = down ? g_bd.val | (1<<num) : g_bd.val & ~(1 << num); g_bd.press = 1; wake_up_interruptible(&g_bd.bwq); } } /* * buttons_interrupt * 使用一个整形变量 key_value 的 0~7 位来记录键值,0~7 * 位分别对应 KEY0~KEY7 的抬起或者按下情况( 1 表示按下)。 */ static irqreturn_t buttons_interrupt(int irq,void *dev_id) { /* 定义一个指针,指向所对应的中断号 */ button_irq_t *birq = (button_irq_t *)dev_id; g_bd.cnum = birq->num; /* 延迟 20ms,用作按键消抖 */ schedule_delayed_work(&g_bd.dwork,HZ/50); return IRQ_RETVAL(IRQ_HANDLED); } /* * tiny6410_buttons_open */ static int tiny6410_buttons_open(struct inode *inode,struct file *file) { int i; int err = 0; for(i = 0;i < sizeof(button_irqs) / sizeof(button_irqs[0]);i ++ ) { if (button_irqs[i].irq < 0) continue; /* 申请中断 */ err = request_irq(button_irqs[i].irq,buttons_interrupt, IRQ_TYPE_EDGE_BOTH, button_irqs[i].name, (void *)&button_irqs[i]); if (err) break; } if(err) { i--; for(;i >= 0;i -- ) { if(button_irqs[i].irq < 0) continue; disable_irq(button_irqs[i].irq); free_irq(button_irqs[i].irq,(void *)&button_irqs[i]); } return -EBUSY; } // ev_press = 1; return 0; } /* * tiny6410_buttons_close */ static int tiny6410_buttons_close(struct inode *inode,struct file *file) { int i; for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i ++ ) { if(button_irqs[i].irq < 0) continue; free_irq(button_irqs[i].irq,(void *)&button_irqs[i]); } return 0; } /* * tiny6410_buttons_read */ static int tiny6410_buttons_read(struct file *filp,char __user *buff, size_t count,loff_t *offp) { unsigned long err; if(!g_bd.press) { if(filp->f_flags & O_NONBLOCK) return -EAGAIN; else wait_event_interruptible(g_bd.bwq,g_bd.press); } g_bd.press = 0; err = copy_to_user((void *)buff,(const void *)(&g_bd.val), min(sizeof(&g_bd.val),count)); return err ? -EFAULT : min(sizeof(&g_bd.val),count); } /* * poll 实现函数 */ static unsigned int tiny6410_buttons_poll(struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file,&g_bd.bwq,wait); if(g_bd.press) mask |= POLLIN | POLLRDNORM; return mask; } /* * file_operation */ static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = tiny6410_buttons_open, .release = tiny6410_buttons_close, .read = tiny6410_buttons_read, .poll = tiny6410_buttons_poll, }; /* * 混合设备结构体 */ static struct miscdevice tiny6410_buttons_misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; /* * probe 实现函数 */ static int tiny6410_buttons_probe(struct platform_device *pdev) { int ret; int i; static struct resource *buttons_irq; printk("[call %s]\n", __func__); /* 初始化等待队列 */ init_waitqueue_head(&g_bd.bwq); /* 初始化 delay_work 结构,来使用延迟调度工作 */ INIT_DELAYED_WORK(&g_bd.dwork,buttons_work_func); /* 获取设备资源 */ for(i = 0;i < 8;i ++ ) { buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i); button_irqs[i].irq = buttons_irq->start; } ret = misc_register(&tiny6410_buttons_misc); return 0; } /* * remove 实现函数 */ static int tiny6410_buttons_remove(struct platform_device *dev) { misc_deregister(&tiny6410_buttons_misc); return 0; } /* 平台设备驱动结构 */ static struct platform_driver tiny6410_buttons_driver = { .probe = tiny6410_buttons_probe, .remove = tiny6410_buttons_remove, .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, }, }; static int __init buttons_init(void) { printk("[Call buttons_init!]\n"); /* 注册驱动 */ platform_driver_register(&tiny6410_buttons_driver); return 0; } static void __exit buttons_exit(void) { printk("[Call buttons_exit!]\n"); platform_driver_unregister(&tiny6410_buttons_driver); } module_init(buttons_init); module_exit(buttons_exit); MODULE_AUTHOR("_Justin"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Tiny6410 Buttons Driver");
③、Makefile
ifneq ($(KERNELRELEASE),) obj-m := plat_btn_dev.o plat_btn_drv.o else KDIR := /home/_Jana/linux-2.6.38 all: make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux- clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order endif
2、测试程序
①、app_btn.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/select.h> #include <time.h> #define DEVICE_NAME "/dev/tiny6410_buttons" static int key_value = 0; int main(void) { int fd, ret; fd_set rfds; int last_kval = key_value; if(-1 == (fd = open(DEVICE_NAME,O_RDONLY))) { printf("open %s error\n",DEVICE_NAME); _exit(EXIT_FAILURE); } /* 先清空集合 */ FD_ZERO(&rfds); /* 设置要监控的文件描述符 */ FD_SET(fd,&rfds); printf("Test for tiny6410_buttons: ...\n"); while(1) { if(-1 == (ret = select(fd + 1,&rfds,NULL,NULL,NULL))) { printf("select error\n"); _exit(EXIT_FAILURE); } if(FD_ISSET(fd,&rfds)) { read(fd, &key_value, sizeof(key_value)); int i; for(i = 0;i < 8;i ++ ) { if((key_value & (1 << i)) != (last_kval & (1 << i))) { printf("KEY%d: %s (key_value=0x%x)\n", i+1, (key_value& (1<<i))? "DOWN": "UP", key_value); } } last_kval = key_value; } } _exit(EXIT_SUCCESS); }
3、测试结果
相关文章推荐
- 【Tiny6410 And Linux】—(2.3)—使用工作队列处理按键中断——原理
- 中断处理中tasklet与工作队列的使用
- 按键驱动程序设计---混杂设备、中断分层处理、工作队列、阻塞型驱动
- 中断处理中tasklet与工作队列的使用
- 中断后半段处理,tasklet使用机制与工作队列
- 【Tiny6410 And Linux】——基于 platform 总线的按键驱动——代码
- linux中断处理下文: 工作队列分析
- 中断分层处理-工作队列
- 中断的下半部处理机制(2)工作队列
- 中断处理的工作队列机制
- 【Tiny6410 And Linux】—(5.1)—RamDisk 驱动实现(内核缺省的处理函数 __make_request())——代码
- 中断处理的工作队列机制-原来如此
- 中断处理的tasklet(小任务)机制和workqueue(工作队列)机制
- 中断处理的tasklet(小任务)机制和workqueue(工作队列)机制
- linux驱动开发之输入子系统编程(一)使用工作队列实现中断下半部
- 《Linux设备驱动开发详解》-- Linux中断处理底半部机制(tasklet、工作队列和软中断)
- 【Tiny6410 And Linux】—(2.2)—Linux 中断处理——原理
- 中断处理机制与工作队列
- Linux内核中断底半部处理--工作队列
- 中断处理的工作队列机制