#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/irqflags.h>
#include <linux/irq.h>
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/plat-s3c24xx/irq.h>
/* GPIO引脚地址 */
#define S3C2440_GPFCON 0x56000050
#define S3C2440_GPGCON 0x56000060
#define DEVICE_NAME "s3c2440_buttons_poll"
static unsigned int major;
static struct class *s3c2440_buttons_class;
static struct class_device *s3c2440_buttons_dev;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static struct fasync_struct *s3c2440_buttons_async_queue;
static struct timer_list s3c2440_button_timer;
struct timer_data {
int irq;
void *dev_id;
};
static struct timer_data s3c2440_timer_data;
/* 中断事件标志,中断服务程序将它设置为1,read函数内将它清0 */
static unsigned long ev_press = 0;
static unsigned char key_val;
struct pin_desc
{
unsigned int pin;
unsigned char key_val;
};
static struct pin_desc pins_desc[4] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04},
};
/*
* 确定按键值
*/
static irqreturn_t s3c2440_buttons_handler(int irq, void *dev_id)
{
/* 10ms后启动定时器 */
mod_timer(&s3c2440_button_timer, jiffies + (HZ/100));
s3c2440_timer_data.irq = irq;
s3c2440_timer_data.dev_id = dev_id;
return IRQ_HANDLED;
}
static void s3c2440_buttons_timer(unsigned long data)
{
struct pin_desc *pindesc = (struct pin_desc *)s3c2440_timer_data.dev_id;
if (pindesc == NULL)
return;
unsigned char pinval;
pinval = s3c2410_gpio_getpin(pindesc->pin); /* 读出引脚值 */
if (pinval)
{
/* 按键松开 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 按键按下 */
key_val = pindesc->key_val;
}
ev_press = 1;
wake_up_interruptible(&button_waitq);
kill_fasync(&s3c2440_buttons_async_queue, SIGIO, POLL_IN);
}
static unsigned s3c2440_buttons_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait);
if (ev_press)
mask |= POLLIN | POLLRDBAND;
return mask;
}
static ssize_t s3c2440_buttons_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT0, &pins_desc[0]);
free_irq(IRQ_EINT2, &pins_desc[1]);
free_irq(IRQ_EINT11, &pins_desc[2]);
free_irq(IRQ_EINT19, &pins_desc[3]);
return 0;
}
static ssize_t s3c2440_buttons_open(struct inode *inode, struct file *file)
{
/* 配置按键:GPF0\2和GPG3的引脚为中断引脚
* 注册irqaction处理函数
*/
request_irq(IRQ_EINT0, s3c2440_buttons_handler, IRQT_BOTHEDGE, "s2", &pins_desc[0]);
request_irq(IRQ_EINT2, s3c2440_buttons_handler, IRQT_BOTHEDGE, "s3", &pins_desc[1]);
request_irq(IRQ_EINT11, s3c2440_buttons_handler, IRQT_BOTHEDGE, "s4", &pins_desc[2]);
request_irq(IRQ_EINT19, s3c2440_buttons_handler, IRQT_BOTHEDGE, "s5", &pins_desc[3]);
return 0;
}
static ssize_t s3c2440_buttons_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
return 0;
}
static ssize_t s3c2440_buttons_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned long ret;
if (count < sizeof(key_val))
return -EINVAL;
/* 如果没有按键按下,就休眠 */
wait_event_interruptible(button_waitq, ev_press);
/* 如果有按键被按下,从休眠状态唤醒 */
ret = copy_to_user(buf, &key_val, sizeof(key_val));
ev_press = 0;
return ret;
}
int s3c2440_buttons_fasync(int fd, struct file * file, int on)
{
return fasync_helper(fd, file, on, &s3c2440_buttons_async_queue);
}
static struct file_operations s3c2440_buttons_fops = {
.owner = THIS_MODULE,
.open = s3c2440_buttons_open,
.read = s3c2440_buttons_read,
.write = s3c2440_buttons_write,
.release = s3c2440_buttons_close,
.poll = s3c2440_buttons_poll,
.fasync = s3c2440_buttons_fasync,
};
static int __init s3c2440_buttons_init(void)
{
major = register_chrdev(0, DEVICE_NAME, &s3c2440_buttons_fops);
if (major < 0) {
printk(DEVICE_NAME " can't register major number\n");
return major;
}
s3c2440_buttons_class = class_create(THIS_MODULE, "s3c2440_buttons_poll");
if (IS_ERR(s3c2440_buttons_class))
return PTR_ERR(s3c2440_buttons_class);
/* 在/sys/s3c2440_leds目录下创建一个设备,设备的目录为leds
* 同时触发mdev在/dev目录下生成一个名为leds的设备节点
*/
s3c2440_buttons_dev = class_device_create(s3c2440_buttons_class, NULL, MKDEV(major, 0), NULL, "button_shake");
if (unlikely(IS_ERR(s3c2440_buttons_dev)))
return PTR_ERR(s3c2440_buttons_dev);
init_timer(&s3c2440_button_timer);
s3c2440_button_timer.data = NULL;
s3c2440_button_timer.function = s3c2440_buttons_timer;
add_timer(&s3c2440_button_timer);
printk(DEVICE_NAME " initialized!\n");
return 0;
}
static void __exit s3c2440_buttons_exit(void)
{
/* 卸载驱动程序 */
class_device_destroy(s3c2440_buttons_class, MKDEV(major, 0));
class_destroy(s3c2440_buttons_class);
unregister_chrdev(major, DEVICE_NAME);
del_timer(&s3c2440_button_timer);
printk(DEVICE_NAME " unregister\n");
}
module_init(s3c2440_buttons_init);
module_exit(s3c2440_buttons_exit);
MODULE_LICENSE("GPL");
评论0