完整驱动代码如下:
#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 <linux/interrupt.h> #include <asm/uaccess.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/gpio.h> #define MODULE_NAME_IRQ "button_fasync" #define BUTTON_IRQ_MAJOR 210 static struct class *btn_fasync_class; static unsigned char key_vals[4] = {'0', '0', '0', '0'}; static DECLARE_WAIT_QUEUE_HEAD(btn_fasync_waitq); static DEFINE_MUTEX(btn_lock); static volatile int ev_press = 0; struct fasync_struct *btn_fasync_queue; struct btn_fasync_desc { unsigned int irq_num; unsigned int pin; unsigned int pin_set; unsigned int key_num; unsigned char *btn_name; }; static struct btn_fasync_desc btns_irq_desc[] = { {IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 0, "KEY1"}, /* K1 */ {IRQ_EINT11, S3C2410_GPG(3), S3C2410_GPG3_EINT11, 1, "KEY2"}, /* K2 */ {IRQ_EINT2, S3C2410_GPF(2), S3C2410_GPF2_EINT2, 2, "KEY3"}, /* K3 */ {IRQ_EINT0, S3C2410_GPF(0), S3C2410_GPF0_EINT0, 3, "KEY4"} /* K4 */ }; static irqreturn_t irq_interrupt(int irq, void *dev_id) { struct btn_fasync_desc *btn_fasyncs = (struct btn_fasync_desc *)dev_id; int down; down = !s3c2410_gpio_getpin(btn_fasyncs->pin); if (down != (key_vals[btn_fasyncs->key_num] & 1)) { key_vals[btn_fasyncs->key_num] = '0' + down; ev_press = 1; wake_up_interruptible(&btn_fasync_waitq); kill_fasync(&btn_fasync_queue, SIGIO, POLL_IN); } return IRQ_RETVAL(IRQ_HANDLED); } static int btn_fasync_open (struct inode *inode, struct file *file) { unsigned int i; down(&btn_lock); for (i = 0; i < sizeof(btns_irq_desc)/sizeof(btns_irq_desc[0]); i++) { if (btns_irq_desc[i].irq_num < 0) { continue; } request_irq(btns_irq_desc[i].irq_num, irq_interrupt, IRQ_TYPE_EDGE_BOTH, btns_irq_desc[i].btn_name,(void *)&btns_irq_desc[i]); } return 0; } static ssize_t btn_fasync_read (struct file *filp, char __user *buf, size_t count, loff_t *ppos) { unsigned long cnt; if (!ev_press) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; else wait_event_interruptible(btn_fasync_waitq, ev_press); } ev_press = 0; cnt = copy_to_user(buf, (const void *)key_vals, min(sizeof(key_vals), count)); return cnt ? -EFAULT : min(sizeof(key_vals), count); } static int btn_fasync_close (struct inode *inode, struct file *file) { unsigned int i; for (i = 0; i < sizeof(btns_irq_desc)/sizeof(btns_irq_desc[0]); i++) { if (btns_irq_desc[i].irq_num < 0) { continue; } free_irq(btns_irq_desc[i].irq_num, (void *)&btns_irq_desc[i]); } up(&btn_lock); return 0; } static unsigned int btn_poll (struct file *file, struct poll_table_struct *wait) { unsigned int mask = 0; poll_wait(file, &btn_fasync_waitq, wait); if (ev_press) mask |= POLLIN | POLLRDNORM; return mask; } static int btn_fasync (int fd, struct file *filp, int on) { return fasync_helper(fd, filp, on, &btn_fasync_queue); } static struct file_operations btn_fasync_fops = { .owner = THIS_MODULE, .open = btn_fasync_open, .read = btn_fasync_read, .release = btn_fasync_close, .poll = btn_poll, .fasync = btn_fasync, }; static int __init __btn_fasync_init(void) { unsigned int ret; ret = register_chrdev(BUTTON_IRQ_MAJOR, MODULE_NAME_IRQ, &btn_fasync_fops); btn_fasync_class = class_create(THIS_MODULE, MODULE_NAME_IRQ); device_create(btn_fasync_class, NULL, MKDEV(BUTTON_IRQ_MAJOR, 0), NULL, MODULE_NAME_IRQ); return ret; } static void __exit __btn_fasync_exit(void) { device_destroy(btn_fasync_class, BUTTON_IRQ_MAJOR); class_destroy(btn_fasync_class); unregister_chrdev(BUTTON_IRQ_MAJOR, MODULE_NAME_IRQ); printk("<0>button_fasync module remove.\n"); } module_init(__btn_fasync_init); module_exit(__btn_fasync_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("[email protected]"); MODULE_DESCRIPTION("Button irq_module test for GT2440 Board");
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <sys/types.h> #include <sys/poll.h> int fd; void button_signal_func(int signal_num) { int i; unsigned char key_vals[4] = {'0', '0', '0', '0'}; unsigned char key_tmp_vals[4]; signal_num = signal_num; if (read(fd, key_tmp_vals, sizeof(key_tmp_vals)) != sizeof(key_tmp_vals)) { printf("return values error.\n"); } for (i = 0; i < sizeof(key_vals)/sizeof(key_vals[0]); i++) { if (key_vals[i] != key_tmp_vals[i]) { key_vals[i] = key_tmp_vals[i]; printf("The key %d is %s\n", i+1, key_vals[i] == '0' ? "up" : "down"); } } } int main(int argv,char **argc) { int Oflags; signal(SIGIO, button_signal_func); if (!(fd = open("/dev/button_fasync", O_RDWR))) { printf("open the driver_node error!\n"); return -EINVAL; } fcntl(fd, F_SETOWN, getpid()); Oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, Oflags | FASYNC); while (1) { sleep(1000); } return 0; }
ifeq ($(KERNELRELEASE),) # learn to write Makefile for driver KERN_VERSION = /opt/GTStudio/GT2440/linux-2.6.38.6 PWD := $(shell pwd) #Specify flags for the module compilation. #EXTAR_CFLAGS = -g -O0 # Build Kernerl module modules: $(MAKE) -C $(KERN_VERSION) M=$(PWD) modules modules_install: $(MAKE) -C $(KERN_VERSION) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules* .PHONY: modules modules_install clean else # Kernel module obj-m += btn_fasync_dev.o endif