#include <linux/fs.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/ioport.h> #include <linux/pci.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/irq.h> #include <linux/interrupt.h> #include <asm/mach/irq.h> #include <asm/arch/regs-gpio.h> static int major = 0; static struct class *cls; /* gpecon 0x56000040 */ /* gpfcon 0x56000050 */ /* gpgcon 0x56000060 */ static volatile unsigned long *gpecon; static volatile unsigned long *gpedat; static volatile unsigned long *gpfcon; static volatile unsigned long *gpfdat; static volatile unsigned long *gpgcon; static volatile unsigned long *gpgdat; struct key_desc { int irq; int pin; char *name; char key_val; }; struct key_desc key_desc[] = { {IRQ_EINT0, S3C2410_GPF0, "K10", 1}, /* 松开: 1, 按下: 0x81 */ {IRQ_EINT2, S3C2410_GPF2, "K7", 2}, /* 松开: 2, 按下: 0x82 */ {IRQ_EINT11, S3C2410_GPG3, "K4", 3}, /* 松开: 3, 按下: 0x83 */ {IRQ_EINT19, S3C2410_GPG11, "K1", 4}, /* 松开: 4, 按下: 0x84 */ }; volatile char key = 0; static wait_queue_head_t button_waitq; #define BUF_LEN 10 static char key_buf[BUF_LEN]; static volatile int r = 0, w = 0; static int isEmpty(void) { return (r == w); } static int isFull(void) { return (r == ((w+1)%BUF_LEN)); } static int putData(char val) { if (isFull()) { return -1; } else { key_buf[w] = val; w = (w+1)%BUF_LEN; return 0; } } static int getData(char *p) { if (isEmpty()) { return -1; } else { *p = key_buf[r]; r = (r+1)%BUF_LEN; return 0; } } static irqreturn_t buttons_irq(int irq, void *dev_id) { struct key_desc *kd = (struct key_desc *)dev_id; int up; char key; /* 确定按键: 哪个按键,按下还是松开 */ up = s3c2410_gpio_getpin(kd->pin); // gpfdat, gpgdat if (up) { key = kd->key_val; } else { key = kd->key_val | 0x80; } // printk("key = 0x%x\n", key); putData(key); /* 唤醒应用程序 */ wake_up_interruptible(&button_waitq); //printk("buttons_irq current %s , pid = %d \n", current->comm, current->pid); return IRQ_HANDLED; } int buttons_open(struct inode *inode, struct file *file) { int i; /* 注册中断 */ for (i = 0; i < 4; i++) { request_irq(key_desc[i].irq, buttons_irq, IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, key_desc[i].name, &key_desc[i]); } /* 设置GPIO为中断引脚 * 设置触发方式 * 使能中断 */ /* 设置KSCAN0(GPE11)为输出引脚,输出0 */ *gpecon &= ~(0x3 << 22); *gpecon |= (1 << 22); *gpedat &= ~(1<<11); return 0; } ssize_t buttons_read(struct file *inode, char __user *buf, size_t size, loff_t *offset) { /* 如果没有按键发生, 休眠 */ /* key 等于 0, 才会休眠 * key 非0, 不会休眠 */ // command //printk("current %s , pid = %d before sleep\n", current->comm, current->pid); char key; wait_event_interruptible(button_waitq, !isEmpty()); //printk("current %s , pid = %d after sleep\n", current->comm, current->pid); /* 被唤醒后, 把按键值返回给用户程序 */ getData(&key); copy_to_user(buf, &key, 1); /* 发生了中断, key=xxx */ //key = 0; return 1; } int buttons_close(struct inode *inode, struct file *file) { int i; for (i = 0; i < 4; i++) { free_irq(key_desc[i].irq, &key_desc[i]); } return 0; } static const struct file_operations buttons_fops = { .owner = THIS_MODULE, .read = buttons_read, .open = buttons_open, /* 设置引脚,申请资源 */ .release = buttons_close, }; int buttons_init(void) { int i; major = register_chrdev(0, "buttons", &buttons_fops); /* sysfs ==> 挂接到/sys */ cls = class_create(THIS_MODULE, "buttons_class"); class_device_create(cls, NULL, MKDEV(major, 0), NULL, "buttons"); // mdev会根据/sys下的这些内容创建/dev/buttons gpecon = ioremap(0x56000040, 4096); gpedat = gpecon + 1; gpfcon = gpecon + 4; gpfdat = gpfcon + 1; gpgcon = gpecon + 8; gpgdat = gpgcon + 1; init_waitqueue_head(&button_waitq); return 0; } void buttons_exit(void) { unregister_chrdev(major, "buttons"); class_device_destroy(cls, MKDEV(major, 0)); class_destroy(cls); iounmap(gpecon); } module_init(buttons_init); module_exit(buttons_exit); MODULE_LICENSE("GPL"); |