基于mini6410的linux按键驱动实例分析

1、 button.c源代码

#include <linux/module.h>

#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/irq.h>#include <asm/irq.h>#include <asm/io.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <mach/hardware.h>#include <linux/platform_device.h>#include <linux/cdev.h>#include <linux/miscdevice.h>#include <mach/map.h>#include <mach/regs-clock.h>#include <mach/regs-gpio.h>#include <plat/gpio-cfg.h>#include <mach/gpio-bank-n.h>#include <mach/gpio-bank-l.h>#define DEVICE_NAME "my_buttons"struct button_irq_desc { int irq; int number; char *name;};static struct button_irq_desc button_irqs [] = { {IRQ_EINT( 0), 0, "KEY0"}, {IRQ_EINT( 1), 1, "KEY1"}, {IRQ_EINT( 2), 2, "KEY2"}, {IRQ_EINT( 3), 3, "KEY3"}, {IRQ_EINT( 4), 4, "KEY4"}, {IRQ_EINT( 5), 5, "KEY5"}, {IRQ_EINT(19), 6, "KEY6"}, {IRQ_EINT(20), 7, "KEY7"},};static volatile char key_values [] = {‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’};static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //定义并初始化等待队列button_waitqstatic volatile int ev_press = 0;/*中断处理程序*/static irqreturn_t buttons_interrupt(int irq, void *dev_id) //void *dev_id = (void *)&button_irqs[i]申请中断时传进来的参数{ struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; int down; int number; unsigned tmp; udelay(0); number = button_irqs->number; switch(number) { case 0: case 1: case 2: case 3: case 4: case 5: tmp = readl(S3C64XX_GPNDAT);//从内存映射的i/o空间读取32位数据 down = !(tmp & (1<<number)); break; case 6: case 7: tmp = readl(S3C64XX_GPLDAT); down = !(tmp & (1 << (number + 5))); break; default: down = 0; } if (down != (key_values[number] & 1)) { key_values[number] = ‘0’ + down; ev_press = 1; wake_up_interruptible(&button_waitq);/*唤醒阻塞(睡眠)的等待队列*/ } return IRQ_RETVAL(IRQ_HANDLED);}static int s3c64xx_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; } /*为6个按键分别注册6个中断,中断号 处理函数 双边沿触发*/ 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;}static int s3c64xx_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;}static int s3c64xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ unsigned long err; /*如果ev_press为0,表明按键没有按下。为1表明按键按下*/ if (!ev_press) { if (filp->f_flags & O_NONBLOCK) //如果filp->f_flags == O_NONBLOCK,不阻塞,否则阻塞 return -EAGAIN; else wait_event_interruptible(button_waitq, ev_press); //阻塞,当ev_press为真时。立即返回;否则阻塞,并挂在button_waitq>参数所指定的等待队列上 } ev_press = 0; err = copy_to_user((void *)buff, (const void *)(&key_values), min(sizeof(key_values), count)); return err ? -EFAULT : min(sizeof(key_values), count);}static unsigned int s3c64xx_buttons_poll( struct file *file, struct poll_table_struct *wait){ unsigned int mask = 0; poll_wait(file, &button_waitq, wait); //使用poll_wait()将等待队列添加到poll_table中 if (ev_press) mask |= POLLIN | POLLRDNORM; //可读掩码 return mask; //返回掩码}/*定义混杂设备操作*/static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = s3c64xx_buttons_open, .release = s3c64xx_buttons_close, .read = s3c64xx_buttons_read, .poll = s3c64xx_buttons_poll,};/*定义混杂设备*/static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, //动态获取混杂设备的次设备号 .name = DEVICE_NAME, //混杂设备名称 .fops = &dev_fops, //混杂设备支持的操作};/*定义模块加载函数*/static int __init dev_init(void){ int ret; ret = misc_register(&misc); //注册混杂设备misc printk (DEVICE_NAME"\tinitialized\n"); return ret;}/*定义模块卸载函数*/static void __exit dev_exit(void){ misc_deregister(&misc); //释放混杂设备}module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("yinjiabin");

2、测试程序appbutton.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/select.h>#include <sys/time.h>#include <errno.h>int main(void){ int buttons_fd; char buttons[6] = {‘0’, ‘0’, ‘0’, ‘0’, ‘0’, ‘0’}; buttons_fd = open("/dev/my_buttons", 0); if(buttons_fd < 0){ perror("open device buttons"); exit(1); } printf("open /dev/my_buttons\n please puton one key\n"); for(;;){ char current_buttons[6]; int count_of_changed_key; int i; if(read(buttons_fd, current_buttons, sizeof current_buttons) != sizeof current_buttons){ perror("read buttons:"); exit(1); } for(i = 0, count_of_changed_key = 0; i < sizeof buttons / sizeof buttons[0]; i++){ if(buttons[i] != current_buttons[i]){ buttons[i] = current_buttons[i]; printf("%s key%d is %s", count_of_changed_key ? "," : "" , i+1, buttons[i] == ‘0’ ? "up" : "down" ); count_of_changed_key++; } } if(count_of_changed_key){ printf("\n"); } } close(buttons_fd); return 0;}就算是一辆永久单车也能让你的梦想走很远。

基于mini6410的linux按键驱动实例分析

相关文章:

你感兴趣的文章:

标签云: