字符设备驱动之按键扫描——FS2410

来源:互联网 发布:数据可视化d3 编辑:程序博客网 时间:2024/05/01 10:49

一、开发环境

1、硬件平台:FS2410

2、主机:Ubuntu 10.10

3、内核版本: linux 2.6.35

4、交叉编译工具链:arm-none-linux-gnueabi-


二、详细代码

button_scan.c:

#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/time.h>#include <linux/irq.h>#include <asm/delay.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/poll.h>#include <asm/irq.h>#include <mach/regs-gpio.h>#define DEVICE_NAME"button"#define GPECON0x56000040#define GPEDAT0x56000044#define GPFCON0x56000050#define GPFDAT0x56000054#define GPGCON0x56000060#define GPGDAT0x56000064#define EXTINT00x56000088#define EXTINT10x5600008C#define EXTINT2 0x56000090static int button_major = 255;struct button_dev{struct cdev cdev;unsigned char key_value;wait_queue_head_t r_wait;};struct button_irq_desc{int irq;};static struct button_irq_desc button_irqs[] = {{IRQ_EINT0}, {IRQ_EINT2}, {IRQ_EINT11}, {IRQ_EINT19},};struct button_dev dev;static volatile unsigned int  *gpecon;static volatile unsigned int  *gpedat;static volatile unsigned int  *gpfcon;static volatile unsigned int  *gpfdat;static volatile unsigned int  *gpgcon;static volatile unsigned int  *gpgdat;static volatile unsigned int *extint0;static volatile unsigned int *extint1;static volatile unsigned int *extint2;static void init_gpio(void){int i;writel(readl(gpecon) & (~((3 << 26) | (3 << 22))), gpecon);writel(readl(gpecon) | ((1 << 26) | (1 << 22)), gpecon);writel(readl(gpedat) & ~((1 << 13) | (1 << 11)), gpedat);writel(readl(gpgcon) & (~((3 << 12) | (3 << 4))), gpgcon);writel(readl(gpgcon) | ((1 << 12) | (1 << 4)), gpgcon);writel(readl(gpgdat) & ~((1 << 6) | (1 << 2)), gpgdat);writel(readl(gpfcon) & (~((3 << 0) | (3 << 4))), gpfcon);writel(readl(gpfcon) | ((2 << 0) | (2 << 4)), gpfcon);writel(readl(gpgcon) & (~((3 << 6) | (3  << 22))), gpgcon);writel(readl(gpgcon) | ((2 << 6) | (2 << 22)), gpgcon);for(i = 0; i < 4; i++){set_irq_type(button_irqs[i].irq, IRQF_TRIGGER_FALLING);}writel(readl(extint0) | (2 << 0), extint0);writel(readl(extint0) | (2 << 8), extint0);writel(readl(extint1) | (2 << 12), extint1);writel(readl(extint2) | (2 << 12), extint2);}static __inline unsigned char button_scan(int irq){//long lGPF, lGPG;     long gpf_value, gpg_value;writel(readl(gpfcon) & ~(3 << 0), gpfcon);writel(readl(gpfcon) & ~(3 << 4), gpfcon);writel(readl(gpgcon) & ~(3 << 22), gpgcon);writel(readl(gpgcon) & ~(3 << 6), gpgcon);writel(readl(gpgdat) & ~(1 << 2), gpgdat);writel(readl(gpgdat) | (1 << 6), gpgdat);writel(readl(gpedat) | (1 << 11), gpedat);writel(readl(gpedat) | (1 << 13), gpedat);gpf_value = readl(gpfdat);gpg_value = readl(gpgdat);if ((gpf_value & (1 << 0)) == 0)return 16;else if((gpf_value & (1 << 2)) == 0)return 15;else if((gpg_value & (1 << 3)) == 0)return 14;else if((gpg_value & (1 << 11)) == 0)return 13;writel(readl(gpgdat) | (1 << 2), gpgdat);writel(readl(gpgdat) & ~(1 << 6), gpgdat);writel(readl(gpedat) | (1 << 11), gpedat);writel(readl(gpedat) | (1 << 13), gpedat);gpf_value = readl(gpfdat);gpg_value = readl(gpgdat);if ((gpf_value & (1 << 0)) == 0)return 11;else if((gpf_value & (1 << 2)) == 0)return 8;else if((gpg_value & (1 << 3)) == 0)return 5;else if((gpg_value & (1 << 11)) == 0)return 2;writel(readl(gpgdat) | (1 << 2), gpgdat);writel(readl(gpgdat) | (1 << 6), gpgdat);writel(readl(gpedat) & ~(1 << 11), gpedat);writel(readl(gpedat) | (1 << 13), gpedat);gpf_value = readl(gpfdat);gpg_value = readl(gpgdat);if ((gpf_value & (1 << 0)) == 0)return 10;else if((gpf_value & (1 << 2)) == 0)return 7;else if((gpg_value & (1 << 3)) == 0)return 4;else if((gpg_value & (1 << 11)) == 0)return 1;writel(readl(gpgdat) | (1 << 2), gpgdat);writel(readl(gpgdat) | (1 << 6), gpgdat);writel(readl(gpedat) | (1 << 11), gpedat);writel(readl(gpedat) & ~(1 << 13), gpedat);gpf_value = readl(gpfdat);gpg_value = readl(gpgdat);if ((gpf_value & (1 << 0)) == 0)return 12;else if((gpf_value & (1 << 2)) == 0)return 9;else if((gpg_value & (1 << 3)) == 0)return 6;else if((gpg_value & (1 << 11)) == 0)return 3;return 0 ;}static irqreturn_t button_interrupt(int irq, void *dev_id){__udelay(50000);dev.key_value = button_scan(irq);init_gpio();wake_up_interruptible(&dev.r_wait);return IRQ_HANDLED;}static int request_irqs(void){int ret;int i;for(i = 0; i < 4; i++){ret = request_irq(button_irqs[i].irq, button_interrupt, IRQF_DISABLED, DEVICE_NAME, NULL);if(ret < 0){free_irq(button_irqs[i].irq, NULL);return ret;}}return 0;}static __inline void free_irqs(void){int i;for(i = 0; i < 4; i++){free_irq(button_irqs[i].irq, NULL);}return;}void ioremap_gpio(void){gpecon = ioremap(GPECON, 0x4);gpedat = ioremap(GPEDAT, 0x4);gpfcon = ioremap(GPFCON, 0x4);gpfdat = ioremap(GPFDAT, 0x4);gpgcon = ioremap(GPGCON, 0x4);gpgdat = ioremap(GPGDAT, 0x4);extint0 = ioremap(EXTINT0, 0x4);extint1 = ioremap(EXTINT1, 0x4);extint2 = ioremap(EXTINT2, 0x4);return ;}static int button_open(struct inode *inode,struct file *filp) {ioremap_gpio();init_gpio();return 0;}static int button_release(struct inode *inode,struct file *filp){    return 0;}static ssize_t button_read(struct file *filp, char *buf, size_t size, loff_t *ppos){int ret;if(copy_to_user(buf, &dev.key_value, size)){ret = -EAGAIN;return ret;}ret = size;dev.key_value = 0;return ret;}static ssize_t button_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos){return 0;}static int button_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){return 0;}static unsigned int button_poll(struct file *filp, poll_table *wait){unsigned int mask = 0;poll_wait(filp, &dev.r_wait, wait);if(dev.key_value != 0)mask |= POLLIN | POLLRDNORM;return mask;}static struct file_operations button_fops ={.owner = THIS_MODULE,.ioctl = button_ioctl,.open = button_open,.read = button_read,.write = button_write,.release = button_release,.poll = button_poll,};static void button_setup_cdev(struct cdev *dev, int index){int err;int devno = MKDEV(button_major, index);cdev_init(dev, &button_fops);dev->owner=THIS_MODULE;err = cdev_add(dev, devno, 1);if(err)printk("Error %d adding button %d\n", err, index);return ;}static int  __init button_init(void){int result;int devno = MKDEV(button_major, 0);request_irqs();if(button_major)result = register_chrdev_region(devno, 1, "button");else{result = alloc_chrdev_region(&devno, 0, 1, "button");button_major = MAJOR(devno);}if(result < 0)return result;printk("button_major : %d\n", button_major);button_setup_cdev(&dev.cdev, 0);init_waitqueue_head(&dev.r_wait);return 0;}void iounmap_gpio(void){iounmap(gpecon);iounmap(gpedat);iounmap(gpfcon);iounmap(gpfdat);iounmap(gpgcon);iounmap(gpgdat);return ;}static void __exit button_exit(void){free_irqs();iounmap_gpio();cdev_del(&dev.cdev);unregister_chrdev_region(MKDEV(button_major, 0), 1);}module_init(button_init);module_exit(button_exit);MODULE_AUTHOR("yhr");MODULE_LICENSE("GPL");


应用测试程序:(button_test.c)

#include <stdio.h>#include <stdlib.h>#include <fcntl.h>int main(void){int dev_fd;char buf;fd_set rfds;if((dev_fd = open("/dev/button", O_RDONLY | O_NONBLOCK)) < 0){perror("failed to open button");exit(-1);}while(1){FD_ZERO(&rfds);FD_SET(dev_fd, &rfds);select(dev_fd + 1, &rfds, NULL, NULL, NULL);if(FD_ISSET(dev_fd, &rfds)){read(dev_fd, &buf, 1);printf("key_value : %d\n", buf);}}return 0;}
Makefile:

ifeq ($(KERNELRELEASE),)#KERNELDIR ?= /your/target/source/directory/KERNELDIR ?= /home/linux/linux-2.6.35/ PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*.PHONY: modules modules_install cleanelse    obj-m := button_scan.oendif


原创粉丝点击