#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h> /*delay*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h> /*kmalloc*/
#include <linux/vmalloc.h> /*vmalloc*/
#include <linux/types.h> /*ssize_t*/
#include <linux/fs.h> /*file_operaiotns*/
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm-generic/ioctl.h>
#include <asm-generic/errno-base.h>
/************硬件相关*************/
#include <mach/iomux-mx6dl.h>
#define GPIO_5 IMX_GPIO_NR(1,5)
#define Key_INT_PIN GPIO_5
#define Key_INT_Number gpio_to_irq(Key_INT_PIN)
#define Falling_Trigger "Falling_Trigger\n"
/**主设备号和次设备号**/
#define DEVICE_MAJOR 104
#define DEVICE_MINOR 0
/*在/sys目录创造一个类*/
static struct class *gpio_class;
/*在这个类下,创造一个设备节点*/
static struct cdev *gpio_class_dev;
static struct timer_list buttons_timer;
//定义并初始化等待队列头部
static DECLARE_WAIT_QUEUE_HEAD(Key_Status_Read_Wait);
static int wait_flag = 0;
/*open函数的实现*/
static int gpio_open(struct inode *inode, struct file *file)
{
printk(KERN_ALERT"GPIO OPEN\n");
return 0;
}
/*release函数的实现*/
static int gpio_close(struct inode *inode, struct file *file)
{
return 0;
}
ssize_t Key_Status_Read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
printk("\n-->>start to read\n");
/*******
唤醒一个被wait_event_interruptible()的进程,需要满足:
在 1)condition为真的前提下,2) 调用wake_up()。
wait_event_interruptible(wq, condition) 修改当前进程为TASK_INTERRUPTIBLE状态,
并把进程添加到等待队列wq中, 意味着该进程要等到被唤醒时才能继续运行,
或者被信号打断;如果没有被唤醒或者信号打断,它会一直等下去。
*******/
wait_event_interruptible(Key_Status_Read_Wait, wait_flag);
wait_flag = 0;
printk("-->>read return\n");
if (copy_to_user(buf, Falling_Trigger, strlen(Falling_Trigger)))
return -EFAULT;
return strlen(Falling_Trigger);
}
/*具体的文件操作集合*/
static const struct file_operations gpio_fops =
{
/*这是拥有者*/
.owner = THIS_MODULE,
.open = gpio_open,
.release = gpio_close,
.read = Key_Status_Read,
};
static irqreturn_t Deal_With_KEY_INT(int irq, void *dev_id)
{
printk("-->>interrupt happend!\n");
//10ms(HZ/100)后启动定时器
mod_timer(&buttons_timer, jiffies+HZ/5);
return IRQ_HANDLED;
}
static void buttons_timer_function(unsigned long data)
{
printk("-->>buttons_timer_function\n");
if(gpio_get_value(Key_INT_PIN)==0)
{
wait_flag = 1;
wake_up(&Key_Status_Read_Wait);
}
}
static void KEY_INT_init(void)
{
int ret;
printk("irq = %u\n", Key_INT_PIN);
mxc_iomux_v3_setup_pad(MX6DL_PAD_GPIO_5__GPIO_1_5); //configures a single pad in the iomuxer
ret=gpio_request(Key_INT_PIN, "Key_INT_PIN");
if(ret==0)
{
printk("gpio_request success\n");
}
else
{
printk("gpio_request fail\n");
}
ret=gpio_direction_input(Key_INT_PIN);
if(ret==0)
{
printk("gpio_direction_input success\n");
}
else
{
printk("gpio_direction_input fail\n");
}
ret = request_irq(Key_INT_Number, Deal_With_KEY_INT,\
IRQF_TRIGGER_FALLING, "Deal_With_KEY_INT", NULL);//IRQF_TRIGGER_RISING
if(ret==0)
{
printk("request_irq success=%d\n",Key_INT_Number);
}
else
{
printk("request_irq fail=%d-[%d]\n",Key_INT_Number,ret);
}
}
/*驱动的初始化函数*/
static int gpio_init(void)
{
/*设备初始化*/
int devno;
/*设备号的申请,创建*/
devno = MKDEV(DEVICE_MAJOR,DEVICE_MINOR);/*静态申请设备号*/
gpio_class_dev = cdev_alloc();
cdev_init(gpio_class_dev,&gpio_fops);/*字符设备初始化,绑定相关操作到设备*/
gpio_class_dev->owner = THIS_MODULE;/*设备的拥有者*/
cdev_add(gpio_class_dev,devno,1);/*添加设备到内核*/
register_chrdev(DEVICE_MAJOR,"gpios",&gpio_fops);/*注册设备*/
gpio_class = class_create(THIS_MODULE, "gpios");/*创建设备类,用于自动创建设备文件*/
device_create(gpio_class,NULL,MKDEV(DEVICE_MAJOR,DEVICE_MINOR),NULL,"gpios");/*依据以前创建的设备类,创建设备*/
KEY_INT_init();
/*加定时器防抖动*/
init_timer(&buttons_timer);
buttons_timer.function = buttons_timer_function;
add_timer(&buttons_timer);
return 0;
}
/*退出函数*/
static void gpio_exit(void)
{
free_irq(Key_INT_Number,NULL);
gpio_free(Key_INT_PIN);
/*设备卸载*/
unregister_chrdev(DEVICE_MAJOR,"gpios");
device_destroy(gpio_class,MKDEV(DEVICE_MAJOR,DEVICE_MINOR));
class_destroy(gpio_class);
del_timer(&buttons_timer);
}
/*LICENSE信息*/
MODULE_LICENSE("GPL");
/*卸载和加载*/
module_init(gpio_init);
module_exit(gpio_exit);